dorkos 0.18.0 → 0.19.0

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.
@@ -17494,12 +17494,18 @@ var init_scenario_store = __esm({
17494
17494
  "use strict";
17495
17495
  BUILT_IN_SCENARIOS = {
17496
17496
  "simple-text": async function* (content3) {
17497
- yield { type: "session_status", data: { sessionId: "test-mode", model: "claude-haiku-4-5" } };
17497
+ yield {
17498
+ type: "session_status",
17499
+ data: { sessionId: "test-mode", model: "claude-haiku-4-5" }
17500
+ };
17498
17501
  yield { type: "text_delta", data: { text: `Echo: ${content3}` } };
17499
17502
  yield { type: "done", data: { sessionId: "test-mode" } };
17500
17503
  },
17501
17504
  "tool-call": async function* (_content) {
17502
- yield { type: "session_status", data: { sessionId: "test-mode", model: "claude-haiku-4-5" } };
17505
+ yield {
17506
+ type: "session_status",
17507
+ data: { sessionId: "test-mode", model: "claude-haiku-4-5" }
17508
+ };
17503
17509
  yield {
17504
17510
  type: "tool_call_start",
17505
17511
  data: { toolCallId: "tc-1", toolName: "Bash", status: "running" }
@@ -17507,7 +17513,12 @@ var init_scenario_store = __esm({
17507
17513
  yield {
17508
17514
  type: "tool_call_delta",
17509
17515
  // tool_call_delta uses ToolCallEventSchema: toolCallId, toolName, status are required
17510
- data: { toolCallId: "tc-1", toolName: "Bash", input: '{"command":"echo hi"}', status: "running" }
17516
+ data: {
17517
+ toolCallId: "tc-1",
17518
+ toolName: "Bash",
17519
+ input: '{"command":"echo hi"}',
17520
+ status: "running"
17521
+ }
17511
17522
  };
17512
17523
  yield {
17513
17524
  type: "tool_call_end",
@@ -17517,7 +17528,10 @@ var init_scenario_store = __esm({
17517
17528
  yield { type: "done", data: { sessionId: "test-mode" } };
17518
17529
  },
17519
17530
  "todo-write": async function* (_content) {
17520
- yield { type: "session_status", data: { sessionId: "test-mode", model: "claude-haiku-4-5" } };
17531
+ yield {
17532
+ type: "session_status",
17533
+ data: { sessionId: "test-mode", model: "claude-haiku-4-5" }
17534
+ };
17521
17535
  yield {
17522
17536
  type: "task_update",
17523
17537
  data: { action: "create", task: { id: "1", subject: "Task one", status: "pending" } }
@@ -17533,9 +17547,15 @@ var init_scenario_store = __esm({
17533
17547
  yield { type: "text_delta", data: { text: "Created 3 tasks." } };
17534
17548
  yield { type: "done", data: { sessionId: "test-mode" } };
17535
17549
  },
17536
- "error": async function* (_content) {
17537
- yield { type: "session_status", data: { sessionId: "test-mode", model: "claude-haiku-4-5" } };
17538
- yield { type: "error", data: { message: "Simulated error from TestModeRuntime" } };
17550
+ error: async function* (_content) {
17551
+ yield {
17552
+ type: "session_status",
17553
+ data: { sessionId: "test-mode", model: "claude-haiku-4-5" }
17554
+ };
17555
+ yield {
17556
+ type: "error",
17557
+ data: { message: "Simulated error from TestModeRuntime" }
17558
+ };
17539
17559
  yield { type: "done", data: { sessionId: "test-mode" } };
17540
17560
  }
17541
17561
  };
@@ -55755,7 +55775,7 @@ var require_websocket = __commonJS({
55755
55775
  var http = __require("http");
55756
55776
  var net = __require("net");
55757
55777
  var tls = __require("tls");
55758
- var { randomBytes: randomBytes2, createHash: createHash3 } = __require("crypto");
55778
+ var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
55759
55779
  var { Duplex, Readable: Readable3 } = __require("stream");
55760
55780
  var { URL: URL2 } = __require("url");
55761
55781
  var PerMessageDeflate = require_permessage_deflate();
@@ -56415,7 +56435,7 @@ var require_websocket = __commonJS({
56415
56435
  abortHandshake(websocket, socket, "Invalid Upgrade header");
56416
56436
  return;
56417
56437
  }
56418
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
56438
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
56419
56439
  if (res.headers["sec-websocket-accept"] !== digest) {
56420
56440
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
56421
56441
  return;
@@ -56782,7 +56802,7 @@ var require_websocket_server = __commonJS({
56782
56802
  var EventEmitter4 = __require("events");
56783
56803
  var http = __require("http");
56784
56804
  var { Duplex } = __require("stream");
56785
- var { createHash: createHash3 } = __require("crypto");
56805
+ var { createHash: createHash2 } = __require("crypto");
56786
56806
  var extension2 = require_extension();
56787
56807
  var PerMessageDeflate = require_permessage_deflate();
56788
56808
  var subprotocol = require_subprotocol();
@@ -57083,7 +57103,7 @@ var require_websocket_server = __commonJS({
57083
57103
  );
57084
57104
  }
57085
57105
  if (this._state > RUNNING) return abortHandshake(socket, 503);
57086
- const digest = createHash3("sha1").update(key + GUID).digest("base64");
57106
+ const digest = createHash2("sha1").update(key + GUID).digest("base64");
57087
57107
  const headers = [
57088
57108
  "HTTP/1.1 101 Switching Protocols",
57089
57109
  "Upgrade: websocket",
@@ -68952,7 +68972,8 @@ var RateLimitEventSchema = z.object({
68952
68972
  retryAfter: z.number().optional()
68953
68973
  }).openapi("RateLimitEvent");
68954
68974
  var DoneEventSchema = z.object({
68955
- sessionId: z.string()
68975
+ sessionId: z.string(),
68976
+ messageIds: z.object({ user: z.string(), assistant: z.string() }).optional()
68956
68977
  }).openapi("DoneEvent");
68957
68978
  var SessionStatusEventSchema = z.object({
68958
68979
  sessionId: z.string(),
@@ -69220,7 +69241,9 @@ var HealthResponseSchema = z.object({
69220
69241
  }).openapi("HealthResponse");
69221
69242
  var ServerConfigSchema = z.object({
69222
69243
  version: z.string().openapi({ description: "Current server version" }),
69223
- latestVersion: z.string().nullable().openapi({ description: "Latest available version from npm, or null if dev mode or unknown" }),
69244
+ latestVersion: z.string().nullable().openapi({
69245
+ description: "Latest available version from npm, or null if dev mode or unknown"
69246
+ }),
69224
69247
  isDevMode: z.boolean().openapi({ description: "Whether the server is running a development build" }),
69225
69248
  dismissedUpgradeVersions: z.array(z.string()).openapi({ description: "Versions the user has dismissed upgrade notifications for" }),
69226
69249
  port: z.number().int(),
@@ -71086,7 +71109,7 @@ var SERVER_VERSION = resolveVersion();
71086
71109
  var IS_DEV_BUILD = checkDevBuild(SERVER_VERSION);
71087
71110
  function resolveVersion() {
71088
71111
  if (env.DORKOS_VERSION_OVERRIDE) return env.DORKOS_VERSION_OVERRIDE;
71089
- if (true) return "0.18.0";
71112
+ if (true) return "0.19.0";
71090
71113
  const pkgPath = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "../../package.json");
71091
71114
  return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
71092
71115
  }
@@ -71130,7 +71153,8 @@ router4.get("/", async (req, res) => {
71130
71153
  resolved = await validateBoundary(targetPath);
71131
71154
  } catch (err) {
71132
71155
  if (err instanceof BoundaryError) {
71133
- if (err.code === "NULL_BYTE") return res.status(400).json({ error: err.message, code: err.code });
71156
+ if (err.code === "NULL_BYTE")
71157
+ return res.status(400).json({ error: err.message, code: err.code });
71134
71158
  return res.status(403).json({ error: err.message, code: err.code });
71135
71159
  }
71136
71160
  const code3 = err.code;
@@ -71201,10 +71225,7 @@ import path6 from "path";
71201
71225
 
71202
71226
  // ../shared/dist/config-schema.js
71203
71227
  import { z as z5 } from "zod";
71204
- var SENSITIVE_CONFIG_KEYS = [
71205
- "tunnel.authtoken",
71206
- "tunnel.auth"
71207
- ];
71228
+ var SENSITIVE_CONFIG_KEYS = ["tunnel.authtoken", "tunnel.auth"];
71208
71229
  var ONBOARDING_STEPS = ["discovery", "pulse", "adapters"];
71209
71230
  var OnboardingStepSchema = z5.enum(ONBOARDING_STEPS);
71210
71231
  var OnboardingStateSchema = z5.object({
@@ -71235,7 +71256,11 @@ var UserConfigSchema = z5.object({
71235
71256
  theme: z5.enum(["light", "dark", "system"]).default("system"),
71236
71257
  dismissedUpgradeVersions: z5.array(z5.string()).default(() => []).describe("Version strings the user has dismissed upgrade notifications for")
71237
71258
  }).default(() => ({ theme: "system", dismissedUpgradeVersions: [] })),
71238
- logging: LoggingConfigSchema.default(() => ({ level: "info", maxLogSizeKb: 500, maxLogFiles: 14 })),
71259
+ logging: LoggingConfigSchema.default(() => ({
71260
+ level: "info",
71261
+ maxLogSizeKb: 500,
71262
+ maxLogFiles: 14
71263
+ })),
71239
71264
  relay: z5.object({
71240
71265
  enabled: z5.boolean().default(true),
71241
71266
  dataDir: z5.string().nullable().default(null)
@@ -71375,9 +71400,7 @@ var ConfigManager = class {
71375
71400
  if (error instanceof z6.ZodError) {
71376
71401
  return {
71377
71402
  valid: false,
71378
- errors: error.issues.map(
71379
- (i2) => `${i2.path.join(".")}: ${i2.message}`
71380
- )
71403
+ errors: error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`)
71381
71404
  };
71382
71405
  }
71383
71406
  throw error;
@@ -72291,7 +72314,9 @@ var PluginSourceSchema = z11.object({
72291
72314
  package: z11.string().optional(),
72292
72315
  /** Local file path (absolute or relative to config dir) */
72293
72316
  path: z11.string().optional()
72294
- }).refine((data) => data.package || data.path, { message: "Plugin source must specify either package or path" }).openapi("PluginSource");
72317
+ }).refine((data) => data.package || data.path, {
72318
+ message: "Plugin source must specify either package or path"
72319
+ }).openapi("PluginSource");
72295
72320
  var TelegramAdapterConfigSchema = z11.object({
72296
72321
  token: z11.string().min(1),
72297
72322
  mode: z11.enum(["polling", "webhook"]).default("polling"),
@@ -72609,7 +72634,6 @@ var DiscoveryCandidateSchema = z13.object({
72609
72634
  }).openapi("DiscoveryCandidate");
72610
72635
  var DenialRecordSchema = z13.object({
72611
72636
  path: z13.string().min(1),
72612
- strategy: z13.string().min(1),
72613
72637
  reason: z13.string().optional(),
72614
72638
  deniedBy: z13.string().min(1),
72615
72639
  deniedAt: z13.string().datetime()
@@ -73299,9 +73323,7 @@ registry.registerPath({
73299
73323
  description: "Array of endpoints",
73300
73324
  content: {
73301
73325
  "application/json": {
73302
- schema: z14.array(
73303
- z14.object({ subject: z14.string(), description: z14.string().optional() })
73304
- )
73326
+ schema: z14.array(z14.object({ subject: z14.string(), description: z14.string().optional() }))
73305
73327
  }
73306
73328
  }
73307
73329
  }
@@ -73666,12 +73688,15 @@ function errorHandler(err, _req, res, _next) {
73666
73688
  function requestLogger(req, res, next) {
73667
73689
  const start2 = Date.now();
73668
73690
  res.on("finish", () => {
73669
- logger.debug({
73670
- method: req.method,
73671
- path: req.path,
73672
- status: res.statusCode,
73673
- ms: Date.now() - start2
73674
- }, "request");
73691
+ logger.debug(
73692
+ {
73693
+ method: req.method,
73694
+ path: req.path,
73695
+ status: res.statusCode,
73696
+ ms: Date.now() - start2
73697
+ },
73698
+ "request"
73699
+ );
73675
73700
  });
73676
73701
  next();
73677
73702
  }
@@ -76827,10 +76852,7 @@ data: ${JSON.stringify(event)}
76827
76852
  data: { sessionId, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
76828
76853
  });
76829
76854
  } catch (err) {
76830
- logger.error(
76831
- `[SessionBroadcaster] Callback error for session ${sessionId}:`,
76832
- err
76833
- );
76855
+ logger.error(`[SessionBroadcaster] Callback error for session ${sessionId}:`, err);
76834
76856
  }
76835
76857
  }
76836
76858
  }
@@ -77144,17 +77166,25 @@ function createCanUseTool(session, logFn) {
77144
77166
  "mcp__dorkos__mesh_register",
77145
77167
  "mcp__dorkos__mesh_status",
77146
77168
  "mcp__dorkos__mesh_query_topology",
77147
- "mcp__dorkos__get_current_agent"
77169
+ "mcp__dorkos__get_agent"
77148
77170
  ]);
77149
77171
  if (READ_ONLY_TOOLS.has(toolName) || DORKOS_AGENT_TOOLS.has(toolName)) {
77150
77172
  logFn("[canUseTool] auto-allow safe tool", { toolName, toolUseID: context.toolUseID });
77151
77173
  return { behavior: "allow", updatedInput: input };
77152
77174
  }
77153
77175
  if (session.permissionMode === "default") {
77154
- logFn("[canUseTool] requesting approval", { toolName, permissionMode: "default", toolUseID: context.toolUseID });
77176
+ logFn("[canUseTool] requesting approval", {
77177
+ toolName,
77178
+ permissionMode: "default",
77179
+ toolUseID: context.toolUseID
77180
+ });
77155
77181
  return handleToolApproval(session, context.toolUseID, toolName, input);
77156
77182
  }
77157
- logFn("[canUseTool] auto-allow", { toolName, permissionMode: session.permissionMode, toolUseID: context.toolUseID });
77183
+ logFn("[canUseTool] auto-allow", {
77184
+ toolName,
77185
+ permissionMode: session.permissionMode,
77186
+ toolUseID: context.toolUseID
77187
+ });
77158
77188
  return { behavior: "allow", updatedInput: input };
77159
77189
  };
77160
77190
  }
@@ -77228,11 +77258,7 @@ function buildTaskEvent(toolName, input) {
77228
77258
  }
77229
77259
 
77230
77260
  // ../../apps/server/src/services/runtimes/claude-code/sdk-event-mapper.ts
77231
- var TOOL_CONTEXTUAL_HOOK_EVENTS = /* @__PURE__ */ new Set([
77232
- "PreToolUse",
77233
- "PostToolUse",
77234
- "PostToolUseFailure"
77235
- ]);
77261
+ var TOOL_CONTEXTUAL_HOOK_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
77236
77262
  function mapErrorCategory(subtype) {
77237
77263
  switch (subtype) {
77238
77264
  case "error_max_turns":
@@ -77570,8 +77596,8 @@ DorkOS Relay is a pub/sub message bus for inter-agent communication.
77570
77596
 
77571
77597
  Subject hierarchy:
77572
77598
  relay.agent.{agentId} \u2014 activate a specific agent session
77573
- relay.inbox.query.{UUID} \u2014 ephemeral inbox for relay_query (auto-managed)
77574
- relay.inbox.dispatch.{UUID} \u2014 ephemeral inbox for relay_dispatch (auto-expires after ~35 min)
77599
+ relay.inbox.query.{UUID} \u2014 ephemeral inbox for relay_send_and_wait (auto-managed)
77600
+ relay.inbox.dispatch.{UUID} \u2014 ephemeral inbox for relay_send_async (auto-expires after ~35 min)
77575
77601
  relay.inbox.{agentId} \u2014 persistent agent reply inbox
77576
77602
  relay.human.console.{clientId} \u2014 reach a human in the DorkOS UI
77577
77603
  relay.system.console \u2014 system broadcast channel
@@ -77579,13 +77605,13 @@ Subject hierarchy:
77579
77605
 
77580
77606
  Workflow: Query another agent \u2014 SHORT tasks (\u226410 min, PREFERRED)
77581
77607
  1. mesh_list() to find available agents and their agent IDs
77582
- 2. relay_query(to_subject="relay.agent.{theirAgentId}", payload={task}, from={myAgentId}, timeout_ms=600000)
77608
+ 2. relay_send_and_wait(to_subject="relay.agent.{theirAgentId}", payload={task}, from={myAgentId}, timeout_ms=600000)
77583
77609
  \u2192 Blocks until reply (max 10 min / 600 000 ms)
77584
77610
  \u2192 Returns: { reply, from, replyMessageId, sentMessageId, progress: ProgressEvent[] }
77585
77611
  \u2192 progress[] contains intermediate steps: { type: "progress", step, step_type, text, done: false }
77586
77612
 
77587
77613
  Workflow: Dispatch to another agent \u2014 LONG tasks (>10 min)
77588
- 1. relay_dispatch(to_subject="relay.agent.{theirAgentId}", payload={task}, from={myAgentId})
77614
+ 1. relay_send_async(to_subject="relay.agent.{theirAgentId}", payload={task}, from={myAgentId})
77589
77615
  \u2192 Returns IMMEDIATELY: { messageId, inboxSubject: "relay.inbox.dispatch.{UUID}" }
77590
77616
  2. Poll: relay_inbox(endpoint_subject=inboxSubject, status="unread")
77591
77617
  \u2192 Returns progress events: { type: "progress", step, step_type: "message"|"tool_result", text, done: false }
@@ -77604,13 +77630,13 @@ CONSTRAINT \u2014 Subagent MCP tools: DorkOS MCP tools (relay_*, mesh_*, pulse_*
77604
77630
  inside Claude Code Task() subagents. This is an SDK architectural limitation (subprocesses do not
77605
77631
  inherit the parent MCP server). The orchestrator pattern workaround:
77606
77632
  WRONG: Task("use relay_send to message agent B") \u2190 tools unavailable, silent failure
77607
- RIGHT: 1. Call relay_dispatch() in this (parent) session
77633
+ RIGHT: 1. Call relay_send_async() in this (parent) session
77608
77634
  2. Pass the inboxSubject into the Task() prompt if needed
77609
77635
  3. Poll relay_inbox() in this session after Task() returns
77610
77636
 
77611
77637
  IMPORTANT: When YOU receive a relay message, respond naturally \u2014 do NOT call relay_send.
77612
77638
  Your response is automatically forwarded by the relay system.
77613
- Only call relay_send/relay_query/relay_dispatch to INITIATE a new message.
77639
+ Only call relay_send/relay_send_and_wait/relay_send_async to INITIATE a new message.
77614
77640
 
77615
77641
  relay_list_endpoints returns type ("dispatch"|"query"|"persistent"|"agent"|"unknown") and expiresAt
77616
77642
  (ISO string or null) for each endpoint. Use these to identify active inboxes and their expiry.
@@ -77825,7 +77851,7 @@ var CORE_TOOLS = [
77825
77851
  "mcp__dorkos__ping",
77826
77852
  "mcp__dorkos__get_server_info",
77827
77853
  "mcp__dorkos__get_session_count",
77828
- "mcp__dorkos__get_current_agent"
77854
+ "mcp__dorkos__get_agent"
77829
77855
  ];
77830
77856
  var PULSE_TOOLS = [
77831
77857
  "mcp__dorkos__pulse_list_schedules",
@@ -77839,8 +77865,8 @@ var RELAY_TOOLS = [
77839
77865
  "mcp__dorkos__relay_inbox",
77840
77866
  "mcp__dorkos__relay_list_endpoints",
77841
77867
  "mcp__dorkos__relay_register_endpoint",
77842
- "mcp__dorkos__relay_query",
77843
- "mcp__dorkos__relay_dispatch",
77868
+ "mcp__dorkos__relay_send_and_wait",
77869
+ "mcp__dorkos__relay_send_async",
77844
77870
  // NEW
77845
77871
  "mcp__dorkos__relay_unregister_endpoint"
77846
77872
  // NEW
@@ -77866,10 +77892,7 @@ var BINDING_TOOLS = [
77866
77892
  "mcp__dorkos__binding_create",
77867
77893
  "mcp__dorkos__binding_delete"
77868
77894
  ];
77869
- var TRACE_TOOLS = [
77870
- "mcp__dorkos__relay_get_trace",
77871
- "mcp__dorkos__relay_get_metrics"
77872
- ];
77895
+ var TRACE_TOOLS = ["mcp__dorkos__relay_get_trace", "mcp__dorkos__relay_get_metrics"];
77873
77896
  function resolveToolConfig(agentConfig, deps) {
77874
77897
  const agent = agentConfig ?? {};
77875
77898
  return {
@@ -77947,7 +77970,11 @@ async function* executeSdkQuery(sessionId, content3, session, opts, messageOpts,
77947
77970
  pulseEnabled: isPulseEnabled(),
77948
77971
  globalConfig
77949
77972
  });
77950
- const baseAppend = await buildSystemPromptAppend(effectiveCwd, opts.meshCore ?? void 0, toolConfig);
77973
+ const baseAppend = await buildSystemPromptAppend(
77974
+ effectiveCwd,
77975
+ opts.meshCore ?? void 0,
77976
+ toolConfig
77977
+ );
77951
77978
  const systemPromptAppend = messageOpts?.systemPromptAppend ? `${baseAppend}
77952
77979
 
77953
77980
  ${messageOpts.systemPromptAppend}` : baseAppend;
@@ -77966,9 +77993,12 @@ ${messageOpts.systemPromptAppend}` : baseAppend;
77966
77993
  if (session.hasStarted) {
77967
77994
  sdkOptions.resume = session.sdkSessionId;
77968
77995
  if (session.sdkSessionId === sessionId) {
77969
- logger.debug("[sendMessage] resuming with sdkSessionId === sessionId (expected after server restart)", {
77970
- session: sessionId
77971
- });
77996
+ logger.debug(
77997
+ "[sendMessage] resuming with sdkSessionId === sessionId (expected after server restart)",
77998
+ {
77999
+ session: sessionId
78000
+ }
78001
+ );
77972
78002
  }
77973
78003
  }
77974
78004
  const cwdSource = messageOpts?.cwd ? "opts.cwd" : opts.sessionCwd ? "session.cwd" : "default";
@@ -78355,32 +78385,41 @@ var ClaudeCodeRuntime = class _ClaudeCodeRuntime {
78355
78385
  }
78356
78386
  }
78357
78387
  const session = this.sessions.get(sessionId);
78358
- yield* executeSdkQuery(sessionId, content3, session, {
78359
- cwd: this.cwd,
78360
- sessionCwd: session.cwd,
78361
- claudeCliPath: this.claudeCliPath,
78362
- meshCore: this.meshCore,
78363
- mcpServerFactory: this.mcpServerFactory,
78364
- onModelsReceived: !this.cachedModels ? (models) => {
78365
- this.cachedModels = models;
78366
- logger.debug("[sendMessage] cached supported models", {
78367
- count: models.length
78368
- });
78369
- } : void 0,
78370
- onMcpStatusReceived: (servers) => {
78371
- const key = opts?.cwd || session.cwd || this.cwd;
78372
- this.cachedMcpStatus.set(key, servers);
78373
- logger.debug("[sendMessage] cached MCP server status", { cwd: key, count: servers.length });
78374
- },
78375
- onCommandsReceived: !this.cachedSdkCommands ? (commands) => {
78376
- this.cachedSdkCommands = commands;
78377
- logger.debug("[sendMessage] cached supported commands", {
78378
- count: commands.length
78379
- });
78380
- } : void 0,
78381
- sdkSessionIndex: this.sdkSessionIndex,
78382
- sessionMapKey: sessionId
78383
- }, opts);
78388
+ yield* executeSdkQuery(
78389
+ sessionId,
78390
+ content3,
78391
+ session,
78392
+ {
78393
+ cwd: this.cwd,
78394
+ sessionCwd: session.cwd,
78395
+ claudeCliPath: this.claudeCliPath,
78396
+ meshCore: this.meshCore,
78397
+ mcpServerFactory: this.mcpServerFactory,
78398
+ onModelsReceived: !this.cachedModels ? (models) => {
78399
+ this.cachedModels = models;
78400
+ logger.debug("[sendMessage] cached supported models", {
78401
+ count: models.length
78402
+ });
78403
+ } : void 0,
78404
+ onMcpStatusReceived: (servers) => {
78405
+ const key = opts?.cwd || session.cwd || this.cwd;
78406
+ this.cachedMcpStatus.set(key, servers);
78407
+ logger.debug("[sendMessage] cached MCP server status", {
78408
+ cwd: key,
78409
+ count: servers.length
78410
+ });
78411
+ },
78412
+ onCommandsReceived: !this.cachedSdkCommands ? (commands) => {
78413
+ this.cachedSdkCommands = commands;
78414
+ logger.debug("[sendMessage] cached supported commands", {
78415
+ count: commands.length
78416
+ });
78417
+ } : void 0,
78418
+ sdkSessionIndex: this.sdkSessionIndex,
78419
+ sessionMapKey: sessionId
78420
+ },
78421
+ opts
78422
+ );
78384
78423
  }
78385
78424
  // ---------------------------------------------------------------------------
78386
78425
  // Interactive flows
@@ -78631,6 +78670,25 @@ function jsonContent(data, isError2 = false) {
78631
78670
  }
78632
78671
 
78633
78672
  // ../../apps/server/src/services/runtimes/claude-code/mcp-tools/core-tools.ts
78673
+ function resolveAgentCwd(deps, args) {
78674
+ if (!args.agent_id && !args.cwd) {
78675
+ throw new Error("Either agent_id or cwd must be provided to identify the agent.");
78676
+ }
78677
+ if (args.agent_id && args.cwd) {
78678
+ throw new Error("Provide either agent_id or cwd, not both.");
78679
+ }
78680
+ if (args.cwd) {
78681
+ return args.cwd;
78682
+ }
78683
+ if (!deps.meshCore) {
78684
+ throw new Error("Mesh is not enabled. Cannot resolve agent_id without Mesh.");
78685
+ }
78686
+ const projectPath = deps.meshCore.getProjectPath(args.agent_id);
78687
+ if (!projectPath) {
78688
+ throw new Error(`Agent not found: ${args.agent_id}`);
78689
+ }
78690
+ return projectPath;
78691
+ }
78634
78692
  async function handlePing() {
78635
78693
  return {
78636
78694
  content: [
@@ -78664,16 +78722,18 @@ async function handleGetServerInfo(args) {
78664
78722
  };
78665
78723
  }
78666
78724
  function createGetSessionCountHandler(deps) {
78667
- return async function handleGetSessionCount() {
78725
+ return async function handleGetSessionCount(args) {
78668
78726
  try {
78669
- const sessions = await deps.transcriptReader.listSessions(deps.defaultCwd);
78727
+ const resolvedCwd = resolveAgentCwd(deps, args);
78728
+ const sessions = await deps.transcriptReader.listSessions(resolvedCwd);
78670
78729
  return {
78671
78730
  content: [
78672
78731
  {
78673
78732
  type: "text",
78674
78733
  text: JSON.stringify({
78675
78734
  count: sessions.length,
78676
- cwd: deps.defaultCwd
78735
+ cwd: resolvedCwd,
78736
+ ...args.agent_id && { agent_id: args.agent_id }
78677
78737
  })
78678
78738
  }
78679
78739
  ]
@@ -78693,12 +78753,16 @@ function createGetSessionCountHandler(deps) {
78693
78753
  }
78694
78754
  };
78695
78755
  }
78696
- function createGetCurrentAgentHandler(deps) {
78697
- return async () => {
78756
+ function createGetAgentHandler(deps) {
78757
+ return async (args) => {
78698
78758
  try {
78699
- const manifest = await readManifest(deps.defaultCwd);
78759
+ const resolvedCwd = resolveAgentCwd(deps, args);
78760
+ const manifest = await readManifest(resolvedCwd);
78700
78761
  if (!manifest) {
78701
- return jsonContent({ agent: null, message: "No agent registered for current directory" });
78762
+ return jsonContent({
78763
+ agent: null,
78764
+ message: "No agent registered for the specified directory"
78765
+ });
78702
78766
  }
78703
78767
  return jsonContent({ agent: manifest });
78704
78768
  } catch (err) {
@@ -78709,9 +78773,13 @@ function createGetCurrentAgentHandler(deps) {
78709
78773
  }
78710
78774
  };
78711
78775
  }
78776
+ var agentScopeSchema = {
78777
+ agent_id: z16.string().optional().describe("Agent ULID to scope the query to"),
78778
+ cwd: z16.string().optional().describe("Working directory path to scope the query to")
78779
+ };
78712
78780
  function getCoreTools(deps) {
78713
78781
  const handleGetSessionCount = createGetSessionCountHandler(deps);
78714
- const handleGetCurrentAgent = createGetCurrentAgentHandler(deps);
78782
+ const handleGetAgent = createGetAgentHandler(deps);
78715
78783
  return [
78716
78784
  tool(
78717
78785
  "ping",
@@ -78727,15 +78795,15 @@ function getCoreTools(deps) {
78727
78795
  ),
78728
78796
  tool(
78729
78797
  "get_session_count",
78730
- "Returns the number of sessions visible in the SDK transcript directory.",
78731
- {},
78798
+ "Returns the number of sessions for a specific agent. Provide either agent_id (ULID) or cwd (working directory path).",
78799
+ agentScopeSchema,
78732
78800
  handleGetSessionCount
78733
78801
  ),
78734
78802
  tool(
78735
- "get_current_agent",
78736
- "Get the agent identity for the current working directory. Returns the agent manifest from .dork/agent.json if one exists, or null if no agent is registered.",
78737
- {},
78738
- handleGetCurrentAgent
78803
+ "get_agent",
78804
+ "Get the agent manifest for a specific agent. Provide either agent_id (ULID) or cwd (working directory path). Returns the agent manifest from .dork/agent.json if one exists, or null if no agent is registered.",
78805
+ agentScopeSchema,
78806
+ handleGetAgent
78739
78807
  )
78740
78808
  ];
78741
78809
  }
@@ -78774,7 +78842,10 @@ function createCreateScheduleHandler(deps) {
78774
78842
  });
78775
78843
  deps.pulseStore.updateSchedule(schedule.id, { status: "pending_approval" });
78776
78844
  const updated = deps.pulseStore.getSchedule(schedule.id);
78777
- return jsonContent({ schedule: updated, note: "Schedule created with pending_approval status. User must approve before it runs." });
78845
+ return jsonContent({
78846
+ schedule: updated,
78847
+ note: "Schedule created with pending_approval status. User must approve before it runs."
78848
+ });
78778
78849
  };
78779
78850
  }
78780
78851
  function createUpdateScheduleHandler(deps) {
@@ -78894,7 +78965,11 @@ function createRelaySendHandler(deps) {
78894
78965
  replyTo: args.replyTo,
78895
78966
  budget: args.budget
78896
78967
  });
78897
- return jsonContent({ messageId: result2.messageId, deliveredTo: result2.deliveredTo, queued: result2.deliveredTo === 0 });
78968
+ return jsonContent({
78969
+ messageId: result2.messageId,
78970
+ deliveredTo: result2.deliveredTo,
78971
+ queued: result2.deliveredTo === 0
78972
+ });
78898
78973
  } catch (e2) {
78899
78974
  const message = e2 instanceof Error ? e2.message : "Publish failed";
78900
78975
  const code3 = message.includes("Access denied") ? "ACCESS_DENIED" : message.includes("Invalid subject") ? "INVALID_SUBJECT" : "PUBLISH_FAILED";
@@ -78978,7 +79053,10 @@ function createRelayQueryHandler(deps) {
78978
79053
  });
78979
79054
  if (result2.deliveredTo === 0 && result2.rejected && result2.rejected.length > 0) {
78980
79055
  const reason = result2.rejected[0]?.reason ?? "unknown";
78981
- return jsonContent({ error: `Message rejected: ${reason}`, code: "REJECTED", reason }, true);
79056
+ return jsonContent(
79057
+ { error: `Message rejected: ${reason}`, code: "REJECTED", reason },
79058
+ true
79059
+ );
78982
79060
  }
78983
79061
  sentMessageId = result2.messageId;
78984
79062
  } catch (e2) {
@@ -78993,7 +79071,9 @@ function createRelayQueryHandler(deps) {
78993
79071
  };
78994
79072
  const timer = setTimeout(() => {
78995
79073
  cleanup();
78996
- reject(new Error(`relay_query timed out after ${timeoutMs}ms (sent ${sentMessageId})`));
79074
+ reject(
79075
+ new Error(`relay_send_and_wait timed out after ${timeoutMs}ms (sent ${sentMessageId})`)
79076
+ );
78997
79077
  }, timeoutMs);
78998
79078
  const unsub = relay.subscribe(inboxSubject, (envelope) => {
78999
79079
  const payload = envelope.payload;
@@ -79071,7 +79151,10 @@ function createRelayUnregisterEndpointHandler(deps) {
79071
79151
  try {
79072
79152
  const removed = await deps.relayCore.unregisterEndpoint(args.subject);
79073
79153
  if (!removed) {
79074
- return jsonContent({ error: `Endpoint not found: ${args.subject}`, code: "ENDPOINT_NOT_FOUND" }, true);
79154
+ return jsonContent(
79155
+ { error: `Endpoint not found: ${args.subject}`, code: "ENDPOINT_NOT_FOUND" },
79156
+ true
79157
+ );
79075
79158
  }
79076
79159
  return jsonContent({ success: true, subject: args.subject });
79077
79160
  } catch (e2) {
@@ -79126,13 +79209,15 @@ function getRelayTools(deps) {
79126
79209
  createRelayRegisterEndpointHandler(deps)
79127
79210
  ),
79128
79211
  tool3(
79129
- "relay_query",
79212
+ "relay_send_and_wait",
79130
79213
  'Send a message to an agent and WAIT for the reply in a single call. Preferred over relay_send + relay_inbox polling for request/reply patterns. Internally registers an ephemeral inbox, sends the message with replyTo set, and blocks until the target agent replies or the timeout elapses. Response shape: { reply, progress, from, replyMessageId, sentMessageId }. progress: array of intermediate steps emitted before the final reply (empty [] for quick replies; populated for multi-step CCA tasks). Each progress step: { type: "progress", step: number, step_type: "message"|"tool_result", text: string, done: false }. Callers that only use { reply, from, replyMessageId } are unaffected \u2014 progress is additive.',
79131
79214
  {
79132
79215
  to_subject: z18.string().describe('Target subject for the message (e.g., "relay.agent.{agentId}")'),
79133
79216
  payload: z18.unknown().describe("Message payload (any JSON-serializable value)"),
79134
79217
  from: z18.string().describe("Sender subject identifier"),
79135
- timeout_ms: z18.number().int().min(1e3).max(6e5).optional().describe("Max milliseconds to wait for a reply (default: 60000, max: 600000). For tasks longer than 10 min, use relay_dispatch instead."),
79218
+ timeout_ms: z18.number().int().min(1e3).max(6e5).optional().describe(
79219
+ "Max milliseconds to wait for a reply (default: 60000, max: 600000). For tasks longer than 10 min, use relay_send_async instead."
79220
+ ),
79136
79221
  budget: z18.object({
79137
79222
  maxHops: z18.number().int().min(1).optional().describe("Max hop count"),
79138
79223
  ttl: z18.number().int().optional().describe("Unix timestamp (ms) expiry"),
@@ -79142,8 +79227,8 @@ function getRelayTools(deps) {
79142
79227
  createRelayQueryHandler(deps)
79143
79228
  ),
79144
79229
  tool3(
79145
- "relay_dispatch",
79146
- "Dispatch a message to an agent and return IMMEDIATELY with a dispatch inbox subject. Unlike relay_query (which blocks), relay_dispatch returns { messageId, inboxSubject } at once. Agent B runs asynchronously; CCA publishes incremental progress events and a final agent_result to the inbox. Poll relay_inbox(endpoint_subject=inboxSubject) for updates. When you receive a message with done:true, call relay_unregister_endpoint(inboxSubject) to clean up.",
79230
+ "relay_send_async",
79231
+ "Dispatch a message to an agent and return IMMEDIATELY with a dispatch inbox subject. Unlike relay_send_and_wait (which blocks), relay_send_async returns { messageId, inboxSubject } at once. Agent B runs asynchronously; CCA publishes incremental progress events and a final agent_result to the inbox. Poll relay_inbox(endpoint_subject=inboxSubject) for updates. When you receive a message with done:true, call relay_unregister_endpoint(inboxSubject) to clean up.",
79147
79232
  {
79148
79233
  to_subject: z18.string().describe('Target subject (e.g., "relay.agent.{agentId}")'),
79149
79234
  payload: z18.unknown().describe("Message payload"),
@@ -79158,7 +79243,7 @@ function getRelayTools(deps) {
79158
79243
  ),
79159
79244
  tool3(
79160
79245
  "relay_unregister_endpoint",
79161
- "Unregister a Relay endpoint. Use to clean up dispatch inboxes after relay_dispatch completes (when done:true received).",
79246
+ "Unregister a Relay endpoint. Use to clean up dispatch inboxes after relay_send_async completes (when done:true received).",
79162
79247
  {
79163
79248
  subject: z18.string().describe("Subject of the endpoint to unregister")
79164
79249
  },
@@ -79172,7 +79257,10 @@ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
79172
79257
  import { z as z19 } from "zod";
79173
79258
  function requireAdapterManager(deps) {
79174
79259
  if (!deps.adapterManager) {
79175
- return jsonContent({ error: "Relay adapters are not enabled", code: "ADAPTERS_DISABLED" }, true);
79260
+ return jsonContent(
79261
+ { error: "Relay adapters are not enabled", code: "ADAPTERS_DISABLED" },
79262
+ true
79263
+ );
79176
79264
  }
79177
79265
  return null;
79178
79266
  }
@@ -79259,7 +79347,10 @@ import { tool as tool5 } from "@anthropic-ai/claude-agent-sdk";
79259
79347
  import { z as z20 } from "zod";
79260
79348
  function requireBindingStore(deps) {
79261
79349
  if (!deps.bindingStore) {
79262
- return jsonContent({ error: "Relay bindings are not enabled", code: "BINDINGS_DISABLED" }, true);
79350
+ return jsonContent(
79351
+ { error: "Relay bindings are not enabled", code: "BINDINGS_DISABLED" },
79352
+ true
79353
+ );
79263
79354
  }
79264
79355
  return null;
79265
79356
  }
@@ -79304,12 +79395,7 @@ function createBindingDeleteHandler(deps) {
79304
79395
  function getBindingTools(deps) {
79305
79396
  if (!deps.bindingStore) return [];
79306
79397
  return [
79307
- tool5(
79308
- "binding_list",
79309
- "List all adapter-to-agent bindings.",
79310
- {},
79311
- createBindingListHandler(deps)
79312
- ),
79398
+ tool5("binding_list", "List all adapter-to-agent bindings.", {}, createBindingListHandler(deps)),
79313
79399
  tool5(
79314
79400
  "binding_create",
79315
79401
  "Create a new adapter-to-agent binding. Maps an external adapter to a specific agent directory.",
@@ -79394,14 +79480,24 @@ function createMeshDiscoverHandler(deps) {
79394
79480
  if (err) return err;
79395
79481
  try {
79396
79482
  const candidates = [];
79483
+ const autoImported = [];
79397
79484
  for await (const event of deps.meshCore.discover(args.roots, {
79398
79485
  maxDepth: args.maxDepth
79399
79486
  })) {
79400
79487
  if (event.type === "candidate") {
79401
79488
  candidates.push(event.data);
79489
+ } else if (event.type === "auto-import" && args.includeRegistered) {
79490
+ autoImported.push(event.data);
79402
79491
  }
79403
79492
  }
79404
- return jsonContent({ candidates, count: candidates.length });
79493
+ return jsonContent({
79494
+ candidates,
79495
+ count: candidates.length,
79496
+ ...args.includeRegistered && {
79497
+ registered: autoImported,
79498
+ registeredCount: autoImported.length
79499
+ }
79500
+ });
79405
79501
  } catch (e2) {
79406
79502
  const message = e2 instanceof Error ? e2.message : "Discovery failed";
79407
79503
  return jsonContent({ error: message, code: "DISCOVER_FAILED" }, true);
@@ -79413,11 +79509,6 @@ function createMeshRegisterHandler(deps) {
79413
79509
  const err = requireMesh(deps);
79414
79510
  if (err) return err;
79415
79511
  try {
79416
- const overrides = {};
79417
- if (args.name) overrides.name = args.name;
79418
- if (args.description) overrides.description = args.description;
79419
- if (args.runtime) overrides.runtime = args.runtime;
79420
- if (args.capabilities) overrides.capabilities = args.capabilities;
79421
79512
  const agent = await deps.meshCore.registerByPath(
79422
79513
  args.path,
79423
79514
  {
@@ -79494,7 +79585,10 @@ function createMeshInspectHandler(deps) {
79494
79585
  if (err) return err;
79495
79586
  const result2 = deps.meshCore.inspect(args.agentId);
79496
79587
  if (!result2) {
79497
- return { content: [{ type: "text", text: `Agent ${args.agentId} not found` }], isError: true };
79588
+ return {
79589
+ content: [{ type: "text", text: `Agent ${args.agentId} not found` }],
79590
+ isError: true
79591
+ };
79498
79592
  }
79499
79593
  return jsonContent(result2);
79500
79594
  };
@@ -79512,10 +79606,13 @@ function getMeshTools(deps) {
79512
79606
  return [
79513
79607
  tool7(
79514
79608
  "mesh_discover",
79515
- "Scan directories for agent candidates. Returns paths with detected runtime, capabilities, and suggested names.",
79609
+ "Scan directories for agent candidates. By default returns only unregistered agents (candidates). Set includeRegistered to also see already-registered agents found during the scan.",
79516
79610
  {
79517
79611
  roots: z22.array(z22.string()).describe("Root directories to scan for agents"),
79518
- maxDepth: z22.number().int().min(1).optional().describe("Maximum directory depth (default 3)")
79612
+ maxDepth: z22.number().int().min(1).optional().describe("Maximum directory depth (default: 5)"),
79613
+ includeRegistered: z22.boolean().optional().describe(
79614
+ "Include already-registered agents in results (default: false \u2014 unregistered candidates only)"
79615
+ )
79519
79616
  },
79520
79617
  createMeshDiscoverHandler(deps)
79521
79618
  ),
@@ -84996,7 +85093,9 @@ var PulseStore = class {
84996
85093
  conditions.push(eq(pulseRuns.scheduleId, opts.scheduleId));
84997
85094
  }
84998
85095
  if (opts.status) {
84999
- conditions.push(eq(pulseRuns.status, opts.status));
85096
+ conditions.push(
85097
+ eq(pulseRuns.status, opts.status)
85098
+ );
85000
85099
  }
85001
85100
  const query2 = this.db.select().from(pulseRuns).orderBy(desc(pulseRuns.createdAt)).limit(limit).offset(offset);
85002
85101
  if (conditions.length > 0) {
@@ -85968,7 +86067,9 @@ var SchedulerService = class {
85968
86067
  this.store.updateRun(run.id, {
85969
86068
  status: "running"
85970
86069
  });
85971
- logger2.info(`relay dispatch for run ${run.id} delivered to ${result2.deliveredTo} endpoint(s)`);
86070
+ logger2.info(
86071
+ `relay dispatch for run ${run.id} delivered to ${result2.deliveredTo} endpoint(s)`
86072
+ );
85972
86073
  }
85973
86074
  }
85974
86075
  /** Execute a run directly via AgentManager — manages AbortController, streams output, updates status. */
@@ -86235,7 +86336,6 @@ import * as os5 from "node:os";
86235
86336
  import fs14 from "node:fs";
86236
86337
 
86237
86338
  // ../relay/dist/endpoint-registry.js
86238
- import { createHash } from "node:crypto";
86239
86339
  import { mkdir as mkdir2, rm } from "node:fs/promises";
86240
86340
  import { join as join4 } from "node:path";
86241
86341
 
@@ -86327,10 +86427,6 @@ function matchTokens(subject, pattern, si, pi) {
86327
86427
 
86328
86428
  // ../relay/dist/endpoint-registry.js
86329
86429
  var MAILDIR_DIRS = ["tmp", "new", "cur", "failed"];
86330
- var HASH_LENGTH = 12;
86331
- function hashSubject(subject) {
86332
- return createHash("sha256").update(subject).digest("hex").slice(0, HASH_LENGTH);
86333
- }
86334
86430
  var EndpointRegistry = class {
86335
86431
  /** Base directory for all endpoint mailboxes (e.g. `~/.dork/relay/mailboxes`). */
86336
86432
  mailboxesDir;
@@ -86348,8 +86444,8 @@ var EndpointRegistry = class {
86348
86444
  /**
86349
86445
  * Register a new message endpoint.
86350
86446
  *
86351
- * Validates the subject, computes a deterministic hash, creates the
86352
- * Maildir directory structure, and stores the endpoint info in memory.
86447
+ * Validates the subject, creates the Maildir directory structure using
86448
+ * the subject string as the directory name, and stores the endpoint info in memory.
86353
86449
  *
86354
86450
  * @param subject - The hierarchical subject for this endpoint (e.g. `relay.agent.myproject.backend`).
86355
86451
  * Must not contain wildcards (`*` or `>`).
@@ -86367,14 +86463,13 @@ var EndpointRegistry = class {
86367
86463
  if (this.endpoints.has(subject)) {
86368
86464
  throw new Error(`Endpoint already registered: ${subject}`);
86369
86465
  }
86370
- const hash = hashSubject(subject);
86371
- const maildirPath = join4(this.mailboxesDir, hash);
86466
+ const maildirPath = join4(this.mailboxesDir, subject);
86372
86467
  for (const dir of MAILDIR_DIRS) {
86373
86468
  await mkdir2(join4(maildirPath, dir), { recursive: true });
86374
86469
  }
86375
86470
  const info = {
86376
86471
  subject,
86377
- hash,
86472
+ hash: subject,
86378
86473
  maildirPath,
86379
86474
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
86380
86475
  };
@@ -88162,11 +88257,10 @@ var AdapterDelivery = class _AdapterDelivery {
88162
88257
  })
88163
88258
  ]);
88164
88259
  if (result2 && result2.success) {
88165
- const subjectHash = hashSubject(subject);
88166
88260
  this.sqliteIndex.insertMessage({
88167
88261
  id: envelope.id,
88168
88262
  subject,
88169
- endpointHash: `adapter:${subjectHash}`,
88263
+ endpointHash: `adapter:${subject}`,
88170
88264
  status: "delivered",
88171
88265
  createdAt: envelope.createdAt,
88172
88266
  expiresAt: null
@@ -88477,10 +88571,9 @@ var RelayPublishPipeline = class {
88477
88571
  }
88478
88572
  /** Dead-letter a message that had no delivery targets. */
88479
88573
  async deadLetter(subject, envelope, adapterResult) {
88480
- const subjectHash = hashSubject(subject);
88481
- await this.deps.maildirStore.ensureMaildir(subjectHash);
88574
+ await this.deps.maildirStore.ensureMaildir(subject);
88482
88575
  const reason = adapterResult?.error ? `adapter delivery failed: ${adapterResult.error}` : "no matching endpoints or adapters";
88483
- await this.deps.deadLetterQueue.reject(subjectHash, envelope, reason);
88576
+ await this.deps.deadLetterQueue.reject(subject, envelope, reason);
88484
88577
  }
88485
88578
  /** Record a trace span for delivery tracking (best-effort). */
88486
88579
  recordTrace(messageId, subject, deliveredTo, rejected, adapterResult, envelope) {
@@ -89057,6 +89150,7 @@ var BaseRelayAdapter = class {
89057
89150
  };
89058
89151
 
89059
89152
  // ../relay/dist/adapter-registry.js
89153
+ var ADAPTER_START_TIMEOUT_MS = 3e4;
89060
89154
  var AdapterRegistry = class {
89061
89155
  adapters = /* @__PURE__ */ new Map();
89062
89156
  relay = null;
@@ -89093,7 +89187,19 @@ var AdapterRegistry = class {
89093
89187
  throw new Error("AdapterRegistry: relay not set \u2014 call setRelay() before registering adapters");
89094
89188
  }
89095
89189
  const existing = this.adapters.get(adapter.id);
89096
- await adapter.start(this.relay);
89190
+ this.logger.info(`AdapterRegistry: starting adapter '${adapter.id}'`);
89191
+ let timer;
89192
+ try {
89193
+ await Promise.race([
89194
+ adapter.start(this.relay),
89195
+ new Promise((_4, reject) => {
89196
+ timer = setTimeout(() => reject(new Error(`Adapter '${adapter.id}' start timed out after ${ADAPTER_START_TIMEOUT_MS / 1e3}s`)), ADAPTER_START_TIMEOUT_MS);
89197
+ })
89198
+ ]);
89199
+ } finally {
89200
+ clearTimeout(timer);
89201
+ }
89202
+ this.logger.info(`AdapterRegistry: adapter '${adapter.id}' started`);
89097
89203
  this.adapters.set(adapter.id, adapter);
89098
89204
  if (existing) {
89099
89205
  try {
@@ -101989,12 +102095,18 @@ var import_grammy = __toESM(require_mod2(), 1);
101989
102095
  import crypto4 from "node:crypto";
101990
102096
  import { createServer } from "node:http";
101991
102097
  var DEFAULT_WEBHOOK_PORT = 8443;
101992
- async function startWebhookMode(bot, adapterId, webhookUrl, webhookPort, webhookSecret) {
102098
+ async function startWebhookMode(bot, adapterId, webhookUrl, webhookPort, webhookSecret, timeoutMs = 15e3) {
101993
102099
  if (!webhookUrl) {
101994
102100
  throw new Error(`TelegramAdapter(${adapterId}): webhookUrl is required when mode is 'webhook'`);
101995
102101
  }
101996
102102
  const secret = webhookSecret ?? crypto4.randomUUID();
101997
- await bot.api.setWebhook(webhookUrl, { secret_token: secret });
102103
+ let timer;
102104
+ await Promise.race([
102105
+ bot.api.setWebhook(webhookUrl, { secret_token: secret }),
102106
+ new Promise((_4, reject) => {
102107
+ timer = setTimeout(() => reject(new Error("Telegram bot token validation timed out \u2014 check your token and network connectivity")), timeoutMs);
102108
+ })
102109
+ ]).finally(() => clearTimeout(timer));
101998
102110
  const port = webhookPort ?? DEFAULT_WEBHOOK_PORT;
101999
102111
  const handler = (0, import_grammy.webhookCallback)(bot, "http", { secretToken: secret });
102000
102112
  const server = createServer(handler);
@@ -102127,6 +102239,8 @@ For local development, use a tunnel service (e.g., ngrok, Cloudflare Tunnel).`
102127
102239
  setupInstructions: "Open Telegram and search for @BotFather. Send /newbot, choose a name and username. Copy the token provided."
102128
102240
  };
102129
102241
  var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102242
+ /** Timeout for bot.init() and setWebhook() calls (ms). */
102243
+ static INIT_TIMEOUT_MS = 15e3;
102130
102244
  /** Reconnection delay schedule (ms) -- exponential backoff. */
102131
102245
  static RECONNECT_DELAYS = [5e3, 1e4, 3e4, 6e4, 6e4];
102132
102246
  config;
@@ -102146,7 +102260,7 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102146
102260
  async testConnection() {
102147
102261
  try {
102148
102262
  const bot = new import_grammy2.Bot(this.config.token);
102149
- await bot.init();
102263
+ await this.initBotWithTimeout(bot);
102150
102264
  return { ok: true, botUsername: bot.botInfo.username };
102151
102265
  } catch (err) {
102152
102266
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -102196,7 +102310,11 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102196
102310
  void handleTypingSignal(this.bot, subject, this.outboundState, signal.state);
102197
102311
  });
102198
102312
  if (this.config.mode === "webhook") {
102199
- this.webhookServer = await startWebhookMode(bot, this.id, this.config.webhookUrl, this.config.webhookPort, this.config.webhookSecret);
102313
+ this.logger.info("starting webhook mode", {
102314
+ url: this.config.webhookUrl,
102315
+ port: this.config.webhookPort
102316
+ });
102317
+ this.webhookServer = await startWebhookMode(bot, this.id, this.config.webhookUrl, this.config.webhookPort, this.config.webhookSecret, _TelegramAdapter.INIT_TIMEOUT_MS);
102200
102318
  } else {
102201
102319
  await this.startPollingMode(bot);
102202
102320
  }
@@ -102251,9 +102369,26 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102251
102369
  });
102252
102370
  }
102253
102371
  // --- Private helpers ---
102372
+ /**
102373
+ * Call bot.init() with a timeout guard.
102374
+ *
102375
+ * Prevents indefinite hangs when the Telegram API is unreachable or the
102376
+ * token is invalid but the connection never closes.
102377
+ */
102378
+ async initBotWithTimeout(bot) {
102379
+ let timer;
102380
+ await Promise.race([
102381
+ bot.init(),
102382
+ new Promise((_4, reject) => {
102383
+ timer = setTimeout(() => reject(new Error("Telegram bot token validation timed out \u2014 check your token and network connectivity")), _TelegramAdapter.INIT_TIMEOUT_MS);
102384
+ })
102385
+ ]).finally(() => clearTimeout(timer));
102386
+ }
102254
102387
  /** Start grammy bot in long-polling mode with eager token validation. */
102255
102388
  async startPollingMode(bot) {
102256
- await bot.init();
102389
+ await this.initBotWithTimeout(bot);
102390
+ this.logger.info("bot validated", { username: bot.botInfo.username, mode: "polling" });
102391
+ this.logger.info("starting polling mode");
102257
102392
  bot.start({
102258
102393
  drop_pending_updates: true,
102259
102394
  onStart: () => {
@@ -102396,6 +102531,7 @@ var WebhookAdapter = class extends BaseRelayAdapter {
102396
102531
  * @param _relay - The RelayPublisher (stored by base class; unused here)
102397
102532
  */
102398
102533
  async _start(_relay) {
102534
+ this.logger.info("webhook adapter ready", { subject: this.config.inbound.subject });
102399
102535
  this.nonceInterval = setInterval(() => {
102400
102536
  this.pruneExpiredNonces();
102401
102537
  }, NONCE_PRUNE_INTERVAL_MS);
@@ -102915,7 +103051,11 @@ async function handleTextDelta(textChunk, streaming, nativeStreaming, ctx) {
102915
103051
  return { success: true, durationMs: now - startTime };
102916
103052
  } catch (err) {
102917
103053
  callbacks.recordError(err);
102918
- return { success: false, error: err instanceof Error ? err.message : String(err), durationMs: Date.now() - startTime };
103054
+ return {
103055
+ success: false,
103056
+ error: err instanceof Error ? err.message : String(err),
103057
+ durationMs: Date.now() - startTime
103058
+ };
102919
103059
  }
102920
103060
  }
102921
103061
  async function flushStreamBuffer(ctx) {
@@ -103111,7 +103251,10 @@ ${inputPreview}
103111
103251
  blocks: [
103112
103252
  {
103113
103253
  type: "section",
103114
- text: { type: "mrkdwn", text: ":hourglass: *Tool Approval Timed Out*\n~`" + data.toolName + "`~" }
103254
+ text: {
103255
+ type: "mrkdwn",
103256
+ text: ":hourglass: *Tool Approval Timed Out*\n~`" + data.toolName + "`~"
103257
+ }
103115
103258
  }
103116
103259
  ]
103117
103260
  });
@@ -103160,7 +103303,11 @@ async function deliverMessage2(opts) {
103160
103303
  return { success: true, durationMs: Date.now() - startTime };
103161
103304
  }
103162
103305
  if (!client) {
103163
- return { success: false, error: `SlackAdapter(${adapterId}): not started`, durationMs: Date.now() - startTime };
103306
+ return {
103307
+ success: false,
103308
+ error: `SlackAdapter(${adapterId}): not started`,
103309
+ durationMs: Date.now() - startTime
103310
+ };
103164
103311
  }
103165
103312
  const channelId = extractChannelId(subject);
103166
103313
  if (!channelId) {
@@ -103214,7 +103361,11 @@ async function deliverMessage2(opts) {
103214
103361
  }
103215
103362
  const text6 = truncateText(formatForPlatform(extractPayloadContent(envelope.payload), "slack"), MAX_MESSAGE_LENGTH2);
103216
103363
  logger3.debug(`deliver: standard payload to ${channelId} (${text6.length} chars)`);
103217
- return wrapSlackCall(() => client.chat.postMessage({ channel: channelId, text: text6, ...threadTs ? { thread_ts: threadTs } : {} }), callbacks, startTime, true);
103364
+ return wrapSlackCall(() => client.chat.postMessage({
103365
+ channel: channelId,
103366
+ text: text6,
103367
+ ...threadTs ? { thread_ts: threadTs } : {}
103368
+ }), callbacks, startTime, true);
103218
103369
  }
103219
103370
 
103220
103371
  // ../relay/dist/adapters/slack/slack-adapter.js
@@ -103276,7 +103427,14 @@ var SLACK_MANIFEST = {
103276
103427
  stepId: "create-app",
103277
103428
  title: "Create & Configure a Slack App",
103278
103429
  description: 'Go to api.slack.com/apps \u2192 Create New App \u2192 From Scratch.\n\n1. **Socket Mode** \u2014 Enable it (Settings \u2192 Socket Mode).\n2. **Event Subscriptions** \u2014 Turn on Enable Events, then subscribe to bot events: app_mention, message.channels, message.groups, message.im, message.mpim.\n3. **OAuth & Permissions** \u2014 Add bot token scopes: app_mentions:read, channels:history, channels:read, chat:write, groups:history, groups:read, im:history, im:read, im:write, mpim:history, reactions:read, reactions:write, users:read. Then install the app to your workspace.\n4. **App-Level Token** \u2014 In Basic Information \u2192 App-Level Tokens, generate a token with the connections:write scope.\n\n\u26A0\uFE0F Do NOT enable "Agents & AI Apps" \u2014 it adds user scopes that cause install failures on most workspaces.',
103279
- fields: ["botToken", "appToken", "signingSecret", "streaming", "nativeStreaming", "typingIndicator"]
103430
+ fields: [
103431
+ "botToken",
103432
+ "appToken",
103433
+ "signingSecret",
103434
+ "streaming",
103435
+ "nativeStreaming",
103436
+ "typingIndicator"
103437
+ ]
103280
103438
  }
103281
103439
  ],
103282
103440
  configFields: [
@@ -103360,7 +103518,9 @@ var SLACK_MANIFEST = {
103360
103518
  ],
103361
103519
  setupInstructions: '1. Create a Slack app at api.slack.com/apps (From Scratch, not From Manifest).\n2. Enable Socket Mode (Settings \u2192 Socket Mode).\n3. Enable Event Subscriptions and subscribe to bot events: app_mention, message.channels, message.groups, message.im, message.mpim.\n4. Add bot token scopes under OAuth & Permissions: app_mentions:read, channels:history, channels:read, chat:write, groups:history, groups:read, im:history, im:read, im:write, mpim:history, reactions:read, reactions:write, users:read.\n5. Install the app to your workspace (OAuth & Permissions \u2192 Install).\n6. Copy the Bot User OAuth Token (starts with xoxb-).\n7. Generate an App-Level Token with connections:write scope (Basic Information \u2192 App-Level Tokens).\n8. Copy the Signing Secret from Basic Information.\n\n\u26A0\uFE0F Do NOT enable "Agents & AI Apps" \u2014 it adds user-level scopes that cause invalid_scope errors on most workspace plans.'
103362
103520
  };
103363
- var SlackAdapter = class extends BaseRelayAdapter {
103521
+ var SlackAdapter = class _SlackAdapter extends BaseRelayAdapter {
103522
+ /** Timeout for auth.test() calls (ms). */
103523
+ static INIT_TIMEOUT_MS = 15e3;
103364
103524
  config;
103365
103525
  app = null;
103366
103526
  /** Bot's own user ID — cached after auth.test for echo prevention. */
@@ -103383,7 +103543,7 @@ var SlackAdapter = class extends BaseRelayAdapter {
103383
103543
  try {
103384
103544
  const { WebClient } = await Promise.resolve().then(() => __toESM(require_dist4(), 1));
103385
103545
  const tempClient = new WebClient(this.config.botToken);
103386
- const result2 = await tempClient.auth.test();
103546
+ const result2 = await _SlackAdapter.withInitTimeout(tempClient.auth.test());
103387
103547
  return { ok: true, botUsername: result2.user };
103388
103548
  } catch (err) {
103389
103549
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -103398,8 +103558,12 @@ var SlackAdapter = class extends BaseRelayAdapter {
103398
103558
  socketMode: true,
103399
103559
  logLevel: import_bolt.LogLevel.WARN
103400
103560
  });
103401
- const authResult = await app.client.auth.test();
103561
+ const authResult = await _SlackAdapter.withInitTimeout(app.client.auth.test());
103402
103562
  this.botUserId = authResult.user_id ?? "";
103563
+ this.logger.info("authenticated", {
103564
+ botUserId: this.botUserId,
103565
+ workspace: authResult.team
103566
+ });
103403
103567
  app.message(async ({ event, client }) => {
103404
103568
  await handleInboundMessage2(event, client, relay, this.botUserId, this.makeInboundCallbacks(), this.logger, this.config.typingIndicator ?? "none", this.pendingReactions);
103405
103569
  });
@@ -103417,6 +103581,7 @@ var SlackAdapter = class extends BaseRelayAdapter {
103417
103581
  app.error(async (error) => {
103418
103582
  this.recordError(error);
103419
103583
  });
103584
+ this.logger.info("connecting via Socket Mode");
103420
103585
  await app.start();
103421
103586
  this.app = app;
103422
103587
  }
@@ -103461,6 +103626,21 @@ var SlackAdapter = class extends BaseRelayAdapter {
103461
103626
  logger: this.logger
103462
103627
  });
103463
103628
  }
103629
+ /**
103630
+ * Wrap a promise with a timeout guard.
103631
+ *
103632
+ * Used for auth.test() calls in both `_start()` and `testConnection()` to
103633
+ * prevent indefinite hangs when the Slack API is unreachable.
103634
+ */
103635
+ static async withInitTimeout(promise) {
103636
+ let timer;
103637
+ return Promise.race([
103638
+ promise,
103639
+ new Promise((_4, reject) => {
103640
+ timer = setTimeout(() => reject(new Error("Slack auth.test() timed out \u2014 check your bot token and network connectivity")), _SlackAdapter.INIT_TIMEOUT_MS);
103641
+ })
103642
+ ]).finally(() => clearTimeout(timer));
103643
+ }
103464
103644
  /**
103465
103645
  * Handle a tool approval or denial action from Slack interactive buttons.
103466
103646
  *
@@ -103593,7 +103773,11 @@ var STREAM_EVENT_TYPES = /* @__PURE__ */ new Set([
103593
103773
  async function handleAgentMessage(subject, envelope, context, startTime, config, deps, relay) {
103594
103774
  const agentId = extractAgentId(subject);
103595
103775
  if (!agentId) {
103596
- return { success: false, error: `Could not extract agentId from subject: ${subject}`, durationMs: Date.now() - startTime };
103776
+ return {
103777
+ success: false,
103778
+ error: `Could not extract agentId from subject: ${subject}`,
103779
+ durationMs: Date.now() - startTime
103780
+ };
103597
103781
  }
103598
103782
  const log = deps.logger ?? console;
103599
103783
  if (!deps.agentSessionStore) {
@@ -103685,7 +103869,11 @@ async function handleAgentMessage(subject, envelope, context, startTime, config,
103685
103869
  } catch (err) {
103686
103870
  streamError = err instanceof Error ? err.message : String(err);
103687
103871
  log.error("[CCA] Streaming error:", err);
103688
- deps.traceStore.updateSpan(envelope.id, { status: "failed", processedAt: Date.now(), error: streamError });
103872
+ deps.traceStore.updateSpan(envelope.id, {
103873
+ status: "failed",
103874
+ processedAt: Date.now(),
103875
+ error: streamError
103876
+ });
103689
103877
  } finally {
103690
103878
  clearTimeout(timeout);
103691
103879
  if (!streamedDone && envelope.replyTo && relay) {
@@ -104354,11 +104542,7 @@ async function loadAdapterConfig(configPath) {
104354
104542
  async function saveAdapterConfig(configPath, configs) {
104355
104543
  await mkdir4(dirname3(configPath), { recursive: true });
104356
104544
  const tmpPath = `${configPath}.tmp`;
104357
- await writeFile2(
104358
- tmpPath,
104359
- JSON.stringify({ adapters: configs }, null, 2),
104360
- "utf-8"
104361
- );
104545
+ await writeFile2(tmpPath, JSON.stringify({ adapters: configs }, null, 2), "utf-8");
104362
104546
  await rename2(tmpPath, configPath);
104363
104547
  }
104364
104548
  async function ensureDefaultAdapterConfig(configPath) {
@@ -104382,11 +104566,7 @@ async function ensureDefaultAdapterConfig(configPath) {
104382
104566
  };
104383
104567
  try {
104384
104568
  await mkdir4(dirname3(configPath), { recursive: true });
104385
- await writeFile2(
104386
- configPath,
104387
- JSON.stringify(defaultConfig, null, 2),
104388
- "utf-8"
104389
- );
104569
+ await writeFile2(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
104390
104570
  logger.info("[AdapterConfig] Generated default adapters.json with claude-code adapter");
104391
104571
  } catch (writeErr) {
104392
104572
  logger.warn("[AdapterConfig] Failed to write default config:", writeErr);
@@ -104476,38 +104656,25 @@ function defaultAdapterStatus() {
104476
104656
  async function createAdapter(config, deps, configPath, onPluginManifest) {
104477
104657
  switch (config.type) {
104478
104658
  case "telegram": {
104479
- const adapter = new TelegramAdapter(
104480
- config.id,
104481
- config.config
104482
- );
104659
+ const adapter = new TelegramAdapter(config.id, config.config);
104483
104660
  adapter.setLogger(createTaggedLogger(`telegram:${config.id}`));
104484
104661
  return adapter;
104485
104662
  }
104486
104663
  case "webhook":
104487
- return new WebhookAdapter(
104488
- config.id,
104489
- config.config
104490
- );
104664
+ return new WebhookAdapter(config.id, config.config);
104491
104665
  case "slack": {
104492
- const adapter = new SlackAdapter(
104493
- config.id,
104494
- config.config
104495
- );
104666
+ const adapter = new SlackAdapter(config.id, config.config);
104496
104667
  adapter.setLogger(createTaggedLogger(`slack:${config.id}`));
104497
104668
  return adapter;
104498
104669
  }
104499
104670
  case "claude-code":
104500
- return new ClaudeCodeAdapter(
104501
- config.id,
104502
- config.config,
104503
- {
104504
- agentManager: deps.agentManager,
104505
- traceStore: deps.traceStore,
104506
- pulseStore: deps.pulseStore,
104507
- agentSessionStore: deps.agentSessionStore,
104508
- logger
104509
- }
104510
- );
104671
+ return new ClaudeCodeAdapter(config.id, config.config, {
104672
+ agentManager: deps.agentManager,
104673
+ traceStore: deps.traceStore,
104674
+ pulseStore: deps.pulseStore,
104675
+ agentSessionStore: deps.agentSessionStore,
104676
+ logger
104677
+ });
104511
104678
  case "plugin":
104512
104679
  return loadPluginAdapter(config, configPath, onPluginManifest);
104513
104680
  default:
@@ -104873,7 +105040,10 @@ var AgentSessionStore = class {
104873
105040
  }
104874
105041
  /** Enqueue an atomic persist, serialized to prevent concurrent tmp+rename races. */
104875
105042
  persist() {
104876
- this.writeLock = this.writeLock.then(() => this.doPersist(), () => this.doPersist());
105043
+ this.writeLock = this.writeLock.then(
105044
+ () => this.doPersist(),
105045
+ () => this.doPersist()
105046
+ );
104877
105047
  return this.writeLock;
104878
105048
  }
104879
105049
  /** Atomic tmp+rename write. Must be serialized via writeLock. */
@@ -104939,7 +105109,10 @@ var BindingRouter = class _BindingRouter {
104939
105109
  try {
104940
105110
  await this.saveSessionMap();
104941
105111
  } catch (err) {
104942
- logger.warn("BindingRouter: failed to persist session map after cleanup, will retry on next write", err);
105112
+ logger.warn(
105113
+ "BindingRouter: failed to persist session map after cleanup, will retry on next write",
105114
+ err
105115
+ );
104943
105116
  }
104944
105117
  logger.info(`Cleaned up ${removed} orphaned session mapping(s)`);
104945
105118
  }
@@ -104957,9 +105130,7 @@ var BindingRouter = class _BindingRouter {
104957
105130
  }
104958
105131
  const binding = this.deps.bindingStore.resolve(adapterId, chatId, channelType);
104959
105132
  if (!binding) {
104960
- logger.info(
104961
- `BindingRouter: no binding for adapter=${adapterId} chat=${chatId}, skipping`
104962
- );
105133
+ logger.info(`BindingRouter: no binding for adapter=${adapterId} chat=${chatId}, skipping`);
104963
105134
  return;
104964
105135
  }
104965
105136
  if (binding.canReceive === false) {
@@ -105035,7 +105206,10 @@ var BindingRouter = class _BindingRouter {
105035
105206
  try {
105036
105207
  await this.saveSessionMap();
105037
105208
  } catch (err) {
105038
- logger.warn("BindingRouter: failed to persist session map, will retry on next write", err);
105209
+ logger.warn(
105210
+ "BindingRouter: failed to persist session map, will retry on next write",
105211
+ err
105212
+ );
105039
105213
  }
105040
105214
  return sessionId;
105041
105215
  } finally {
@@ -105071,10 +105245,7 @@ var BindingRouter = class _BindingRouter {
105071
105245
  agentId: binding.agentId,
105072
105246
  projectPath
105073
105247
  });
105074
- const session = await this.deps.agentManager.createSession(
105075
- projectPath,
105076
- binding.permissionMode
105077
- );
105248
+ const session = await this.deps.agentManager.createSession(projectPath, binding.permissionMode);
105078
105249
  return session.id;
105079
105250
  }
105080
105251
  /**
@@ -105134,7 +105305,10 @@ var BindingRouter = class _BindingRouter {
105134
105305
  }
105135
105306
  }
105136
105307
  saveSessionMap() {
105137
- this.writeLock = this.writeLock.then(() => this.doSaveSessionMap(), () => this.doSaveSessionMap());
105308
+ this.writeLock = this.writeLock.then(
105309
+ () => this.doSaveSessionMap(),
105310
+ () => this.doSaveSessionMap()
105311
+ );
105138
105312
  return this.writeLock;
105139
105313
  }
105140
105314
  /** Atomic tmp+rename write of the session map. Must be serialized via writeLock. */
@@ -105267,7 +105441,9 @@ var AdapterManager = class {
105267
105441
  /** Initialize the binding subsystem. Non-fatal on failure — logs and continues. */
105268
105442
  async initBindingSubsystem() {
105269
105443
  if (!this.deps.relayCore || !this.deps.meshCore) {
105270
- logger.info("[AdapterManager] relayCore or meshCore not provided, skipping binding subsystem");
105444
+ logger.info(
105445
+ "[AdapterManager] relayCore or meshCore not provided, skipping binding subsystem"
105446
+ );
105271
105447
  return;
105272
105448
  }
105273
105449
  this.bindingSubsystem = await BindingSubsystem.init({
@@ -105327,7 +105503,11 @@ var AdapterManager = class {
105327
105503
  config.enabled = false;
105328
105504
  await saveAdapterConfig(this.configPath, this.configs);
105329
105505
  await this.registry.unregister(id);
105330
- this.deps.eventRecorder?.insertAdapterEvent(id, "adapter.disconnected", "Disconnected from relay");
105506
+ this.deps.eventRecorder?.insertAdapterEvent(
105507
+ id,
105508
+ "adapter.disconnected",
105509
+ "Disconnected from relay"
105510
+ );
105331
105511
  }
105332
105512
  /**
105333
105513
  * List all adapter configs paired with their current runtime status.
@@ -105353,10 +105533,7 @@ var AdapterManager = class {
105353
105533
  };
105354
105534
  const maskedConfig = {
105355
105535
  ...config,
105356
- config: maskSensitiveFields(
105357
- config.config,
105358
- manifest
105359
- )
105536
+ config: maskSensitiveFields(config.config, manifest)
105360
105537
  };
105361
105538
  return { config: maskedConfig, status };
105362
105539
  }
@@ -105412,6 +105589,7 @@ var AdapterManager = class {
105412
105589
  }
105413
105590
  /** Add a new adapter instance, persist config, and start it if enabled. */
105414
105591
  async addAdapter(type, id, config, enabled = true, label) {
105592
+ logger.info("[AdapterManager] adding adapter", { type, id, enabled });
105415
105593
  if (this.configs.some((c3) => c3.id === id)) {
105416
105594
  throw new AdapterError(`Adapter with ID '${id}' already exists`, "DUPLICATE_ID");
105417
105595
  }
@@ -105438,10 +105616,25 @@ var AdapterManager = class {
105438
105616
  };
105439
105617
  this.configs.push(adapterConfig);
105440
105618
  await saveAdapterConfig(this.configPath, this.configs);
105619
+ logger.debug("[AdapterManager] config saved", { id });
105441
105620
  if (enabled) {
105442
105621
  const adapter = await this.buildAdapter(adapterConfig);
105443
105622
  if (adapter) {
105444
- await this.registry.register(adapter);
105623
+ logger.info("[AdapterManager] starting adapter", { id });
105624
+ try {
105625
+ await this.registry.register(adapter);
105626
+ this.deps.eventRecorder?.insertAdapterEvent(
105627
+ id,
105628
+ "adapter.connected",
105629
+ "Connected to relay"
105630
+ );
105631
+ logger.info("[AdapterManager] adapter registered", { id });
105632
+ } catch (err) {
105633
+ const message = err instanceof Error ? err.message : String(err);
105634
+ this.deps.eventRecorder?.insertAdapterEvent(id, "adapter.error", message);
105635
+ logger.error("[AdapterManager] adapter start failed", { id, error: message });
105636
+ throw err;
105637
+ }
105445
105638
  }
105446
105639
  }
105447
105640
  }
@@ -105614,10 +105807,7 @@ var AdapterManager = class {
105614
105807
  if (manifest.setupGuide) continue;
105615
105808
  try {
105616
105809
  const docsPath = this.resolveAdapterDocsPath(type);
105617
- const setupGuide = await readFile8(
105618
- join12(docsPath, "setup.md"),
105619
- "utf-8"
105620
- );
105810
+ const setupGuide = await readFile8(join12(docsPath, "setup.md"), "utf-8");
105621
105811
  this.manifests.set(type, { ...manifest, setupGuide });
105622
105812
  } catch {
105623
105813
  }
@@ -105934,7 +106124,10 @@ function createRelayRouter(relayCore2, adapterManager2, traceStore2) {
105934
106124
  return res.json(publishResult);
105935
106125
  } catch (err) {
105936
106126
  const message = err instanceof Error ? err.message : "Publish failed";
105937
- return res.status(422).json({ error: message, code: err?.code ?? "PUBLISH_FAILED" });
106127
+ return res.status(422).json({
106128
+ error: message,
106129
+ code: err?.code ?? "PUBLISH_FAILED"
106130
+ });
105938
106131
  }
105939
106132
  });
105940
106133
  router13.get("/messages", (_req, res) => {
@@ -106009,9 +106202,7 @@ function createRelayRouter(relayCore2, adapterManager2, traceStore2) {
106009
106202
  });
106010
106203
  router13.get("/dead-letters", async (_req, res) => {
106011
106204
  const endpointHash = _req.query.endpointHash;
106012
- const deadLetters = await relayCore2.getDeadLetters(
106013
- endpointHash ? { endpointHash } : void 0
106014
- );
106205
+ const deadLetters = await relayCore2.getDeadLetters(endpointHash ? { endpointHash } : void 0);
106015
106206
  return res.json(deadLetters);
106016
106207
  });
106017
106208
  router13.get("/dead-letters/aggregated", async (_req, res) => {
@@ -106308,9 +106499,7 @@ var TraceStore = class {
106308
106499
  const rows = this.db.select({
106309
106500
  metadata: relayTraces.metadata,
106310
106501
  sentAt: relayTraces.sentAt
106311
- }).from(relayTraces).where(
106312
- sql`json_extract(${relayTraces.metadata}, '$.adapterId') = ${adapterId}`
106313
- ).all();
106502
+ }).from(relayTraces).where(sql`json_extract(${relayTraces.metadata}, '$.adapterId') = ${adapterId}`).all();
106314
106503
  const VALID_CHANNEL_TYPES = /* @__PURE__ */ new Set(["dm", "group", "channel", "thread"]);
106315
106504
  const chatMap = /* @__PURE__ */ new Map();
106316
106505
  for (const row of rows) {
@@ -106705,11 +106894,10 @@ var DenialList = class {
106705
106894
  * onConflictDoUpdate on the unique `path` column.
106706
106895
  *
106707
106896
  * @param filePath - Absolute path to the project directory
106708
- * @param strategy - Strategy name that detected the directory
106709
106897
  * @param reason - Human-readable reason for denial (optional)
106710
106898
  * @param denier - Identifier of the entity performing the denial (e.g., "user", "system")
106711
106899
  */
106712
- deny(filePath, strategy, reason, denier) {
106900
+ deny(filePath, reason, denier) {
106713
106901
  const canonicalPath = this.canonicalize(filePath);
106714
106902
  this.db.insert(agentDenials).values({
106715
106903
  id: generateUlid4(),
@@ -106768,9 +106956,6 @@ var DenialList = class {
106768
106956
  rowToRecord(row) {
106769
106957
  return {
106770
106958
  path: row.path,
106771
- // DenialRecord requires strategy but agentDenials schema doesn't have it;
106772
- // use 'manual' as default since strategy was dropped in the schema migration.
106773
- strategy: "manual",
106774
106959
  reason: row.reason ?? void 0,
106775
106960
  deniedBy: row.denier ?? "unknown",
106776
106961
  deniedAt: row.createdAt
@@ -107167,7 +107352,10 @@ function validateNamespace(ns) {
107167
107352
  return { valid: false, reason: "Namespace must not be empty" };
107168
107353
  }
107169
107354
  if (ns.length > MAX_NAMESPACE_LENGTH) {
107170
- return { valid: false, reason: `Namespace must be at most ${MAX_NAMESPACE_LENGTH} characters (got ${ns.length})` };
107355
+ return {
107356
+ valid: false,
107357
+ reason: `Namespace must be at most ${MAX_NAMESPACE_LENGTH} characters (got ${ns.length})`
107358
+ };
107171
107359
  }
107172
107360
  return { valid: true };
107173
107361
  }
@@ -107258,7 +107446,6 @@ function manifestDiffersFromEntry(manifest, entry) {
107258
107446
 
107259
107447
  // ../mesh/dist/discovery/unified-scanner.js
107260
107448
  import fs18 from "fs/promises";
107261
- import { realpathSync as realpathSync2 } from "fs";
107262
107449
  import path29 from "path";
107263
107450
 
107264
107451
  // ../mesh/dist/discovery/types.js
@@ -107324,7 +107511,7 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107324
107511
  if (followSymlinks) {
107325
107512
  let realDir;
107326
107513
  try {
107327
- realDir = realpathSync2(dir);
107514
+ realDir = await fs18.realpath(dir);
107328
107515
  } catch {
107329
107516
  continue;
107330
107517
  }
@@ -107341,7 +107528,9 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107341
107528
  }
107342
107529
  let entries;
107343
107530
  try {
107344
- entries = await fs18.readdir(dir, { withFileTypes: true });
107531
+ entries = await fs18.readdir(dir, {
107532
+ withFileTypes: true
107533
+ });
107345
107534
  } catch (err) {
107346
107535
  const code3 = err.code;
107347
107536
  if (code3 === "EACCES" || code3 === "EPERM") {
@@ -107379,7 +107568,7 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107379
107568
  for (const entry of entries) {
107380
107569
  const isDir = entry.isDirectory();
107381
107570
  const isSymlink = entry.isSymbolicLink();
107382
- if (!isDir && !(followSymlinks && isSymlink))
107571
+ if (!isDir && !isSymlink)
107383
107572
  continue;
107384
107573
  if (isSymlink && !followSymlinks)
107385
107574
  continue;
@@ -107664,9 +107853,8 @@ function listCrossNamespaceRules(deps) {
107664
107853
  }
107665
107854
 
107666
107855
  // ../mesh/dist/mesh-denial.js
107667
- var DEFAULT_REGISTRAR2 = "mesh";
107668
- async function deny(deps, filePath, reason, denier = DEFAULT_REGISTRAR2) {
107669
- deps.denialList.deny(filePath, "manual", reason, denier);
107856
+ async function deny(deps, filePath, reason, denier = DEFAULT_REGISTRAR) {
107857
+ deps.denialList.deny(filePath, reason, denier);
107670
107858
  }
107671
107859
  async function undeny(deps, filePath) {
107672
107860
  deps.denialList.clear(filePath);
@@ -107705,8 +107893,23 @@ var MeshCore = class {
107705
107893
  this.relayBridge = relayBridge;
107706
107894
  this.defaultScanRoot = defaultScanRoot;
107707
107895
  this.logger = logger3;
107708
- this.discoveryDeps = { registry: registry2, denialList, relayBridge, strategies, defaultScanRoot, logger: logger3, generateUlid: monotonicFactory() };
107709
- this.agentDeps = { registry: registry2, relayBridge, topology, signalEmitter: options.signalEmitter, logger: logger3, onUnregisterCallbacks: this.onUnregisterCallbacks };
107896
+ this.discoveryDeps = {
107897
+ registry: registry2,
107898
+ denialList,
107899
+ relayBridge,
107900
+ strategies,
107901
+ defaultScanRoot,
107902
+ logger: logger3,
107903
+ generateUlid: monotonicFactory()
107904
+ };
107905
+ this.agentDeps = {
107906
+ registry: registry2,
107907
+ relayBridge,
107908
+ topology,
107909
+ signalEmitter: options.signalEmitter,
107910
+ logger: logger3,
107911
+ onUnregisterCallbacks: this.onUnregisterCallbacks
107912
+ };
107710
107913
  this.denialDeps = { denialList };
107711
107914
  }
107712
107915
  // --- Discovery & Registration ---
@@ -107908,9 +108111,7 @@ function enrichAgent(agent, namespace, deps, scheduleCounts, relayEndpoints) {
107908
108111
  if (relaySubject && relayEndpoints.length > 0) {
107909
108112
  try {
107910
108113
  const nsPrefix = `relay.agent.${namespace}.`;
107911
- const matchingEndpoints = relayEndpoints.filter(
107912
- (ep) => ep.subject.startsWith(nsPrefix)
107913
- );
108114
+ const matchingEndpoints = relayEndpoints.filter((ep) => ep.subject.startsWith(nsPrefix));
107914
108115
  relayAdapters = matchingEndpoints.map((ep) => ep.subject.slice(nsPrefix.length)).filter(Boolean);
107915
108116
  } catch {
107916
108117
  }
@@ -107984,7 +108185,9 @@ function createMeshRouter(deps) {
107984
108185
  const name = overrides?.name;
107985
108186
  const runtime = overrides?.runtime;
107986
108187
  if (!name || !runtime) {
107987
- return res.status(400).json({ error: "overrides.name and overrides.runtime are required for manual registration" });
108188
+ return res.status(400).json({
108189
+ error: "overrides.name and overrides.runtime are required for manual registration"
108190
+ });
107988
108191
  }
107989
108192
  try {
107990
108193
  const manifest = await meshCore2.registerByPath(
@@ -108307,7 +108510,7 @@ var import_ip_address = __toESM(require_ip_address(), 1);
108307
108510
  import { isIPv6 } from "node:net";
108308
108511
  import { isIPv6 as isIPv62 } from "node:net";
108309
108512
  import { Buffer as Buffer2 } from "node:buffer";
108310
- import { createHash as createHash2 } from "node:crypto";
108513
+ import { createHash } from "node:crypto";
108311
108514
  import { isIP } from "node:net";
108312
108515
  function ipKeyGenerator(ip, ipv6Subnet = 56) {
108313
108516
  if (ipv6Subnet && isIPv6(ip)) {
@@ -108471,7 +108674,7 @@ var getResetSeconds = (windowMs, resetTime) => {
108471
108674
  return resetSeconds;
108472
108675
  };
108473
108676
  var getPartitionKey = (key) => {
108474
- const hash = createHash2("sha256");
108677
+ const hash = createHash("sha256");
108475
108678
  hash.update(key);
108476
108679
  const partitionKey = hash.digest("hex").slice(0, 12);
108477
108680
  return Buffer2.from(partitionKey).toString("base64");
@@ -114801,17 +115004,21 @@ function createExternalMcpServer(deps) {
114801
115004
  },
114802
115005
  handleGetServerInfo
114803
115006
  );
115007
+ const agentScopeSchema2 = {
115008
+ agent_id: z27.string().optional().describe("Agent ULID to scope the query to"),
115009
+ cwd: z27.string().optional().describe("Working directory path to scope the query to")
115010
+ };
114804
115011
  server.tool(
114805
115012
  "get_session_count",
114806
- "Returns the number of sessions visible in the SDK transcript directory.",
114807
- {},
115013
+ "Returns the number of sessions for a specific agent. Provide either agent_id (ULID) or cwd (working directory path).",
115014
+ agentScopeSchema2,
114808
115015
  createGetSessionCountHandler(deps)
114809
115016
  );
114810
115017
  server.tool(
114811
- "get_current_agent",
114812
- "Get the agent identity for the current working directory. Returns the agent manifest from .dork/agent.json if one exists, or null if no agent is registered.",
114813
- {},
114814
- createGetCurrentAgentHandler(deps)
115018
+ "get_agent",
115019
+ "Get the agent manifest for a specific agent. Provide either agent_id (ULID) or cwd (working directory path). Returns the agent manifest from .dork/agent.json if one exists, or null if no agent is registered.",
115020
+ agentScopeSchema2,
115021
+ createGetAgentHandler(deps)
114815
115022
  );
114816
115023
  server.tool(
114817
115024
  "pulse_list_schedules",
@@ -114911,14 +115118,14 @@ function createExternalMcpServer(deps) {
114911
115118
  createRelayRegisterEndpointHandler(deps)
114912
115119
  );
114913
115120
  server.tool(
114914
- "relay_query",
115121
+ "relay_send_and_wait",
114915
115122
  'Send a message to an agent and WAIT for the reply in a single call. Preferred over relay_send + relay_inbox polling for request/reply patterns. Internally registers an ephemeral inbox, sends the message with replyTo set, and blocks until the target agent replies or the timeout elapses. Response shape: { reply, progress, from, replyMessageId, sentMessageId }. progress: array of intermediate steps emitted before the final reply (empty [] for quick replies; populated for multi-step CCA tasks). Each progress step: { type: "progress", step: number, step_type: "message"|"tool_result", text: string, done: false }. Callers that only use { reply, from, replyMessageId } are unaffected \u2014 progress is additive.',
114916
115123
  {
114917
115124
  to_subject: z27.string().describe('Target subject for the message (e.g., "relay.agent.{agentId}")'),
114918
115125
  payload: z27.unknown().describe("Message payload (any JSON-serializable value)"),
114919
115126
  from: z27.string().describe("Sender subject identifier"),
114920
115127
  timeout_ms: z27.number().int().min(1e3).max(6e5).optional().describe(
114921
- "Max milliseconds to wait for a reply (default: 60000, max: 600000). For tasks longer than 10 min, use relay_dispatch instead."
115128
+ "Max milliseconds to wait for a reply (default: 60000, max: 600000). For tasks longer than 10 min, use relay_send_async instead."
114922
115129
  ),
114923
115130
  budget: z27.object({
114924
115131
  maxHops: z27.number().int().min(1).optional().describe("Max hop count"),
@@ -114929,8 +115136,8 @@ function createExternalMcpServer(deps) {
114929
115136
  createRelayQueryHandler(deps)
114930
115137
  );
114931
115138
  server.tool(
114932
- "relay_dispatch",
114933
- "Dispatch a message to an agent and return IMMEDIATELY with a dispatch inbox subject. Unlike relay_query (which blocks), relay_dispatch returns { messageId, inboxSubject } at once. Agent B runs asynchronously; CCA publishes incremental progress events and a final agent_result to the inbox. Poll relay_inbox(endpoint_subject=inboxSubject) for updates. When you receive a message with done:true, call relay_unregister_endpoint(inboxSubject) to clean up.",
115139
+ "relay_send_async",
115140
+ "Dispatch a message to an agent and return IMMEDIATELY with a dispatch inbox subject. Unlike relay_send_and_wait (which blocks), relay_send_async returns { messageId, inboxSubject } at once. Agent B runs asynchronously; CCA publishes incremental progress events and a final agent_result to the inbox. Poll relay_inbox(endpoint_subject=inboxSubject) for updates. When you receive a message with done:true, call relay_unregister_endpoint(inboxSubject) to clean up.",
114934
115141
  {
114935
115142
  to_subject: z27.string().describe('Target subject (e.g., "relay.agent.{agentId}")'),
114936
115143
  payload: z27.unknown().describe("Message payload"),
@@ -114945,7 +115152,7 @@ function createExternalMcpServer(deps) {
114945
115152
  );
114946
115153
  server.tool(
114947
115154
  "relay_unregister_endpoint",
114948
- "Unregister a Relay endpoint. Use to clean up dispatch inboxes after relay_dispatch completes (when done:true received).",
115155
+ "Unregister a Relay endpoint. Use to clean up dispatch inboxes after relay_send_async completes (when done:true received).",
114949
115156
  {
114950
115157
  subject: z27.string().describe("Subject of the endpoint to unregister")
114951
115158
  },
@@ -116383,14 +116590,20 @@ function createMcpRouter(serverFactory) {
116383
116590
  router13.get("/", (_req, res) => {
116384
116591
  res.status(405).json({
116385
116592
  jsonrpc: "2.0",
116386
- error: { code: -32e3, message: "Method not allowed. This server operates in stateless mode." },
116593
+ error: {
116594
+ code: -32e3,
116595
+ message: "Method not allowed. This server operates in stateless mode."
116596
+ },
116387
116597
  id: null
116388
116598
  });
116389
116599
  });
116390
116600
  router13.delete("/", (_req, res) => {
116391
116601
  res.status(405).json({
116392
116602
  jsonrpc: "2.0",
116393
- error: { code: -32e3, message: "Method not allowed. This server operates in stateless mode." },
116603
+ error: {
116604
+ code: -32e3,
116605
+ message: "Method not allowed. This server operates in stateless mode."
116606
+ },
116394
116607
  id: null
116395
116608
  });
116396
116609
  });
@@ -116425,10 +116638,7 @@ function validateMcpOrigin(req, res, next) {
116425
116638
  return;
116426
116639
  }
116427
116640
  const port = env.DORKOS_PORT;
116428
- const allowed = [
116429
- `http://localhost:${port}`,
116430
- `http://127.0.0.1:${port}`
116431
- ];
116641
+ const allowed = [`http://localhost:${port}`, `http://127.0.0.1:${port}`];
116432
116642
  const tunnelUrl = tunnelManager.status.url;
116433
116643
  if (tunnelUrl) {
116434
116644
  allowed.push(new URL(tunnelUrl).origin);
@@ -116499,7 +116709,10 @@ async function start() {
116499
116709
  logger.info("[Runtime] ClaudeCodeRuntime registered as default");
116500
116710
  }
116501
116711
  const schedulerConfig = configManager.get("scheduler");
116502
- const pulseEnabled = env.DORKOS_PULSE_ENABLED || schedulerConfig.enabled;
116712
+ const pulseEnabled = (
116713
+ // eslint-disable-next-line no-restricted-syntax -- Checking presence, not value: env.ts can't distinguish "unset" from "set to false"
116714
+ "DORKOS_PULSE_ENABLED" in process.env ? env.DORKOS_PULSE_ENABLED : schedulerConfig.enabled
116715
+ );
116503
116716
  let pulseStore;
116504
116717
  if (pulseEnabled) {
116505
116718
  try {
@@ -116512,8 +116725,11 @@ async function start() {
116512
116725
  }
116513
116726
  }
116514
116727
  const relayConfig = configManager.get("relay");
116515
- const relayEnabled = "DORKOS_RELAY_ENABLED" in process.env ? env.DORKOS_RELAY_ENABLED : relayConfig?.enabled ?? false;
116516
- const relayDataDir = relayConfig?.dataDir ?? path33.join(dorkHome, "relay");
116728
+ const relayEnabled = (
116729
+ // eslint-disable-next-line no-restricted-syntax -- Checking presence, not value: env.ts can't distinguish "unset" from "set to false"
116730
+ "DORKOS_RELAY_ENABLED" in process.env ? env.DORKOS_RELAY_ENABLED : relayConfig.enabled
116731
+ );
116732
+ const relayDataDir = relayConfig.dataDir ?? path33.join(dorkHome, "relay");
116517
116733
  if (relayEnabled) {
116518
116734
  try {
116519
116735
  adapterRegistry = new AdapterRegistry();
@@ -116595,15 +116811,26 @@ async function start() {
116595
116811
  };
116596
116812
  claudeRuntime.setMcpServerFactory(() => ({ dorkos: createDorkOsToolServer(mcpToolDeps) }));
116597
116813
  const mcpAuthMode = env.MCP_API_KEY ? "auth: API key" : "auth: none";
116598
- app.use("/mcp", validateMcpOrigin, mcpApiKeyAuth, createMcpRouter(() => createExternalMcpServer(mcpToolDeps)));
116814
+ app.use(
116815
+ "/mcp",
116816
+ validateMcpOrigin,
116817
+ mcpApiKeyAuth,
116818
+ createMcpRouter(() => createExternalMcpServer(mcpToolDeps))
116819
+ );
116599
116820
  logger.info(`[MCP] External MCP server mounted at /mcp (stateless, ${mcpAuthMode})`);
116600
116821
  }
116601
116822
  if (pulseEnabled && pulseStore && claudeRuntime) {
116602
- schedulerService = new SchedulerService(pulseStore, claudeRuntime, {
116603
- maxConcurrentRuns: schedulerConfig.maxConcurrentRuns,
116604
- retentionCount: schedulerConfig.retentionCount,
116605
- timezone: schedulerConfig.timezone
116606
- }, relayCore, meshCore);
116823
+ schedulerService = new SchedulerService(
116824
+ pulseStore,
116825
+ claudeRuntime,
116826
+ {
116827
+ maxConcurrentRuns: schedulerConfig.maxConcurrentRuns,
116828
+ retentionCount: schedulerConfig.retentionCount,
116829
+ timezone: schedulerConfig.timezone
116830
+ },
116831
+ relayCore,
116832
+ meshCore
116833
+ );
116607
116834
  app.use("/api/pulse", createPulseRouter(pulseStore, schedulerService, dorkHome, meshCore));
116608
116835
  setPulseEnabled(true);
116609
116836
  logger.info("[Pulse] Routes mounted and scheduler configured");
@@ -116611,7 +116838,9 @@ async function start() {
116611
116838
  meshCore.onUnregister((agentId) => {
116612
116839
  const disabledCount = pulseStore.disableSchedulesByAgentId(agentId);
116613
116840
  if (disabledCount > 0) {
116614
- logger.info(`[Pulse] Disabled ${disabledCount} schedule(s) for unregistered agent ${agentId}`);
116841
+ logger.info(
116842
+ `[Pulse] Disabled ${disabledCount} schedule(s) for unregistered agent ${agentId}`
116843
+ );
116615
116844
  }
116616
116845
  });
116617
116846
  }
@@ -116632,11 +116861,14 @@ async function start() {
116632
116861
  app.use("/api/discovery", createDiscoveryRouter(meshCore));
116633
116862
  logger.info("[Discovery] Routes mounted");
116634
116863
  }
116635
- app.use("/api/admin", createAdminRouter({
116636
- dorkHome,
116637
- shutdownServices,
116638
- closeDb: () => db.$client.close()
116639
- }));
116864
+ app.use(
116865
+ "/api/admin",
116866
+ createAdminRouter({
116867
+ dorkHome,
116868
+ shutdownServices,
116869
+ closeDb: () => db.$client.close()
116870
+ })
116871
+ );
116640
116872
  logger.info("[Admin] Routes mounted");
116641
116873
  finalizeApp(app);
116642
116874
  if (relayCore) {
@@ -116651,12 +116883,9 @@ async function start() {
116651
116883
  logger.info("[Pulse] Scheduler started");
116652
116884
  }
116653
116885
  if (claudeRuntime) {
116654
- healthCheckInterval = setInterval(
116655
- () => {
116656
- claudeRuntime.checkSessionHealth();
116657
- },
116658
- INTERVALS.HEALTH_CHECK_MS
116659
- );
116886
+ healthCheckInterval = setInterval(() => {
116887
+ claudeRuntime.checkSessionHealth();
116888
+ }, INTERVALS.HEALTH_CHECK_MS);
116660
116889
  }
116661
116890
  if (env.TUNNEL_ENABLED) {
116662
116891
  const tunnelPort = env.TUNNEL_PORT ?? PORT;
@@ -116676,7 +116905,10 @@ async function start() {
116676
116905
  ...isDevPort && { mode: `dev (Vite on :${tunnelPort})` }
116677
116906
  });
116678
116907
  } catch (err) {
116679
- logger.warn("[Tunnel] Failed to start ngrok tunnel \u2014 server continues without tunnel.", logError(err));
116908
+ logger.warn(
116909
+ "[Tunnel] Failed to start ngrok tunnel \u2014 server continues without tunnel.",
116910
+ logError(err)
116911
+ );
116680
116912
  }
116681
116913
  }
116682
116914
  }