dorkos 0.17.2 → 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(),
@@ -70918,7 +70941,12 @@ router.post("/:id/approve", async (req, res) => {
70918
70941
  const { toolCallId } = parsed.data;
70919
70942
  const runtime = runtimeRegistry.getDefault();
70920
70943
  const approved = runtime.approveTool(sessionId, toolCallId, true);
70921
- if (!approved) return sendError(res, 404, "No pending approval", "NO_PENDING_APPROVAL");
70944
+ if (!approved) {
70945
+ if (runtime.hasSession(sessionId)) {
70946
+ return sendError(res, 409, "Interaction already resolved", "INTERACTION_ALREADY_RESOLVED");
70947
+ }
70948
+ return sendError(res, 404, "No pending approval", "NO_PENDING_APPROVAL");
70949
+ }
70922
70950
  res.json({ ok: true });
70923
70951
  });
70924
70952
  router.post("/:id/deny", async (req, res) => {
@@ -70931,7 +70959,12 @@ router.post("/:id/deny", async (req, res) => {
70931
70959
  const { toolCallId } = parsed.data;
70932
70960
  const runtime = runtimeRegistry.getDefault();
70933
70961
  const denied = runtime.approveTool(sessionId, toolCallId, false);
70934
- if (!denied) return sendError(res, 404, "No pending approval", "NO_PENDING_APPROVAL");
70962
+ if (!denied) {
70963
+ if (runtime.hasSession(sessionId)) {
70964
+ return sendError(res, 409, "Interaction already resolved", "INTERACTION_ALREADY_RESOLVED");
70965
+ }
70966
+ return sendError(res, 404, "No pending approval", "NO_PENDING_APPROVAL");
70967
+ }
70935
70968
  res.json({ ok: true });
70936
70969
  });
70937
70970
  router.post("/:id/submit-answers", async (req, res) => {
@@ -70944,7 +70977,12 @@ router.post("/:id/submit-answers", async (req, res) => {
70944
70977
  const { toolCallId, answers } = parsed.data;
70945
70978
  const runtime = runtimeRegistry.getDefault();
70946
70979
  const ok3 = runtime.submitAnswers(sessionId, toolCallId, answers);
70947
- if (!ok3) return sendError(res, 404, "No pending question", "NO_PENDING_QUESTION");
70980
+ if (!ok3) {
70981
+ if (runtime.hasSession(sessionId)) {
70982
+ return sendError(res, 409, "Interaction already resolved", "INTERACTION_ALREADY_RESOLVED");
70983
+ }
70984
+ return sendError(res, 404, "No pending question", "NO_PENDING_QUESTION");
70985
+ }
70948
70986
  res.json({ ok: true });
70949
70987
  });
70950
70988
  router.get("/:id/stream", async (req, res) => {
@@ -71071,7 +71109,7 @@ var SERVER_VERSION = resolveVersion();
71071
71109
  var IS_DEV_BUILD = checkDevBuild(SERVER_VERSION);
71072
71110
  function resolveVersion() {
71073
71111
  if (env.DORKOS_VERSION_OVERRIDE) return env.DORKOS_VERSION_OVERRIDE;
71074
- if (true) return "0.17.2";
71112
+ if (true) return "0.19.0";
71075
71113
  const pkgPath = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "../../package.json");
71076
71114
  return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
71077
71115
  }
@@ -71115,7 +71153,8 @@ router4.get("/", async (req, res) => {
71115
71153
  resolved = await validateBoundary(targetPath);
71116
71154
  } catch (err) {
71117
71155
  if (err instanceof BoundaryError) {
71118
- 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 });
71119
71158
  return res.status(403).json({ error: err.message, code: err.code });
71120
71159
  }
71121
71160
  const code3 = err.code;
@@ -71186,10 +71225,7 @@ import path6 from "path";
71186
71225
 
71187
71226
  // ../shared/dist/config-schema.js
71188
71227
  import { z as z5 } from "zod";
71189
- var SENSITIVE_CONFIG_KEYS = [
71190
- "tunnel.authtoken",
71191
- "tunnel.auth"
71192
- ];
71228
+ var SENSITIVE_CONFIG_KEYS = ["tunnel.authtoken", "tunnel.auth"];
71193
71229
  var ONBOARDING_STEPS = ["discovery", "pulse", "adapters"];
71194
71230
  var OnboardingStepSchema = z5.enum(ONBOARDING_STEPS);
71195
71231
  var OnboardingStateSchema = z5.object({
@@ -71220,7 +71256,11 @@ var UserConfigSchema = z5.object({
71220
71256
  theme: z5.enum(["light", "dark", "system"]).default("system"),
71221
71257
  dismissedUpgradeVersions: z5.array(z5.string()).default(() => []).describe("Version strings the user has dismissed upgrade notifications for")
71222
71258
  }).default(() => ({ theme: "system", dismissedUpgradeVersions: [] })),
71223
- logging: LoggingConfigSchema.default(() => ({ level: "info", maxLogSizeKb: 500, maxLogFiles: 14 })),
71259
+ logging: LoggingConfigSchema.default(() => ({
71260
+ level: "info",
71261
+ maxLogSizeKb: 500,
71262
+ maxLogFiles: 14
71263
+ })),
71224
71264
  relay: z5.object({
71225
71265
  enabled: z5.boolean().default(true),
71226
71266
  dataDir: z5.string().nullable().default(null)
@@ -71360,9 +71400,7 @@ var ConfigManager = class {
71360
71400
  if (error instanceof z6.ZodError) {
71361
71401
  return {
71362
71402
  valid: false,
71363
- errors: error.issues.map(
71364
- (i2) => `${i2.path.join(".")}: ${i2.message}`
71365
- )
71403
+ errors: error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`)
71366
71404
  };
71367
71405
  }
71368
71406
  throw error;
@@ -71858,12 +71896,12 @@ var SDK_TOOL_NAMES = {
71858
71896
  };
71859
71897
 
71860
71898
  // ../../apps/server/src/routes/tunnel.ts
71861
- var DEV_CLIENT_PORT = Number(process.env.VITE_PORT) || 4241;
71862
71899
  var router8 = Router8();
71863
71900
  function resolveTunnelPort() {
71864
71901
  if (process.env.TUNNEL_PORT) return Number(process.env.TUNNEL_PORT);
71865
71902
  const isDev = process.env.NODE_ENV !== "production";
71866
- return isDev ? DEV_CLIENT_PORT : Number(process.env.DORKOS_PORT) || DEFAULT_PORT;
71903
+ const devClientPort = Number(process.env.VITE_PORT) || 4241;
71904
+ return isDev ? devClientPort : Number(process.env.DORKOS_PORT) || DEFAULT_PORT;
71867
71905
  }
71868
71906
  router8.get("/status", (_req, res) => {
71869
71907
  res.json(tunnelManager.status);
@@ -72276,7 +72314,9 @@ var PluginSourceSchema = z11.object({
72276
72314
  package: z11.string().optional(),
72277
72315
  /** Local file path (absolute or relative to config dir) */
72278
72316
  path: z11.string().optional()
72279
- }).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");
72280
72320
  var TelegramAdapterConfigSchema = z11.object({
72281
72321
  token: z11.string().min(1),
72282
72322
  mode: z11.enum(["polling", "webhook"]).default("polling"),
@@ -72594,7 +72634,6 @@ var DiscoveryCandidateSchema = z13.object({
72594
72634
  }).openapi("DiscoveryCandidate");
72595
72635
  var DenialRecordSchema = z13.object({
72596
72636
  path: z13.string().min(1),
72597
- strategy: z13.string().min(1),
72598
72637
  reason: z13.string().optional(),
72599
72638
  deniedBy: z13.string().min(1),
72600
72639
  deniedAt: z13.string().datetime()
@@ -73284,9 +73323,7 @@ registry.registerPath({
73284
73323
  description: "Array of endpoints",
73285
73324
  content: {
73286
73325
  "application/json": {
73287
- schema: z14.array(
73288
- z14.object({ subject: z14.string(), description: z14.string().optional() })
73289
- )
73326
+ schema: z14.array(z14.object({ subject: z14.string(), description: z14.string().optional() }))
73290
73327
  }
73291
73328
  }
73292
73329
  }
@@ -73651,12 +73688,15 @@ function errorHandler(err, _req, res, _next) {
73651
73688
  function requestLogger(req, res, next) {
73652
73689
  const start2 = Date.now();
73653
73690
  res.on("finish", () => {
73654
- logger.debug({
73655
- method: req.method,
73656
- path: req.path,
73657
- status: res.statusCode,
73658
- ms: Date.now() - start2
73659
- }, "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
+ );
73660
73700
  });
73661
73701
  next();
73662
73702
  }
@@ -76812,10 +76852,7 @@ data: ${JSON.stringify(event)}
76812
76852
  data: { sessionId, timestamp: (/* @__PURE__ */ new Date()).toISOString() }
76813
76853
  });
76814
76854
  } catch (err) {
76815
- logger.error(
76816
- `[SessionBroadcaster] Callback error for session ${sessionId}:`,
76817
- err
76818
- );
76855
+ logger.error(`[SessionBroadcaster] Callback error for session ${sessionId}:`, err);
76819
76856
  }
76820
76857
  }
76821
76858
  }
@@ -77129,17 +77166,25 @@ function createCanUseTool(session, logFn) {
77129
77166
  "mcp__dorkos__mesh_register",
77130
77167
  "mcp__dorkos__mesh_status",
77131
77168
  "mcp__dorkos__mesh_query_topology",
77132
- "mcp__dorkos__get_current_agent"
77169
+ "mcp__dorkos__get_agent"
77133
77170
  ]);
77134
77171
  if (READ_ONLY_TOOLS.has(toolName) || DORKOS_AGENT_TOOLS.has(toolName)) {
77135
77172
  logFn("[canUseTool] auto-allow safe tool", { toolName, toolUseID: context.toolUseID });
77136
77173
  return { behavior: "allow", updatedInput: input };
77137
77174
  }
77138
77175
  if (session.permissionMode === "default") {
77139
- 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
+ });
77140
77181
  return handleToolApproval(session, context.toolUseID, toolName, input);
77141
77182
  }
77142
- 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
+ });
77143
77188
  return { behavior: "allow", updatedInput: input };
77144
77189
  };
77145
77190
  }
@@ -77213,11 +77258,7 @@ function buildTaskEvent(toolName, input) {
77213
77258
  }
77214
77259
 
77215
77260
  // ../../apps/server/src/services/runtimes/claude-code/sdk-event-mapper.ts
77216
- var TOOL_CONTEXTUAL_HOOK_EVENTS = /* @__PURE__ */ new Set([
77217
- "PreToolUse",
77218
- "PostToolUse",
77219
- "PostToolUseFailure"
77220
- ]);
77261
+ var TOOL_CONTEXTUAL_HOOK_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
77221
77262
  function mapErrorCategory(subtype) {
77222
77263
  switch (subtype) {
77223
77264
  case "error_max_turns":
@@ -77555,8 +77596,8 @@ DorkOS Relay is a pub/sub message bus for inter-agent communication.
77555
77596
 
77556
77597
  Subject hierarchy:
77557
77598
  relay.agent.{agentId} \u2014 activate a specific agent session
77558
- relay.inbox.query.{UUID} \u2014 ephemeral inbox for relay_query (auto-managed)
77559
- 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)
77560
77601
  relay.inbox.{agentId} \u2014 persistent agent reply inbox
77561
77602
  relay.human.console.{clientId} \u2014 reach a human in the DorkOS UI
77562
77603
  relay.system.console \u2014 system broadcast channel
@@ -77564,13 +77605,13 @@ Subject hierarchy:
77564
77605
 
77565
77606
  Workflow: Query another agent \u2014 SHORT tasks (\u226410 min, PREFERRED)
77566
77607
  1. mesh_list() to find available agents and their agent IDs
77567
- 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)
77568
77609
  \u2192 Blocks until reply (max 10 min / 600 000 ms)
77569
77610
  \u2192 Returns: { reply, from, replyMessageId, sentMessageId, progress: ProgressEvent[] }
77570
77611
  \u2192 progress[] contains intermediate steps: { type: "progress", step, step_type, text, done: false }
77571
77612
 
77572
77613
  Workflow: Dispatch to another agent \u2014 LONG tasks (>10 min)
77573
- 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})
77574
77615
  \u2192 Returns IMMEDIATELY: { messageId, inboxSubject: "relay.inbox.dispatch.{UUID}" }
77575
77616
  2. Poll: relay_inbox(endpoint_subject=inboxSubject, status="unread")
77576
77617
  \u2192 Returns progress events: { type: "progress", step, step_type: "message"|"tool_result", text, done: false }
@@ -77589,13 +77630,13 @@ CONSTRAINT \u2014 Subagent MCP tools: DorkOS MCP tools (relay_*, mesh_*, pulse_*
77589
77630
  inside Claude Code Task() subagents. This is an SDK architectural limitation (subprocesses do not
77590
77631
  inherit the parent MCP server). The orchestrator pattern workaround:
77591
77632
  WRONG: Task("use relay_send to message agent B") \u2190 tools unavailable, silent failure
77592
- RIGHT: 1. Call relay_dispatch() in this (parent) session
77633
+ RIGHT: 1. Call relay_send_async() in this (parent) session
77593
77634
  2. Pass the inboxSubject into the Task() prompt if needed
77594
77635
  3. Poll relay_inbox() in this session after Task() returns
77595
77636
 
77596
77637
  IMPORTANT: When YOU receive a relay message, respond naturally \u2014 do NOT call relay_send.
77597
77638
  Your response is automatically forwarded by the relay system.
77598
- 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.
77599
77640
 
77600
77641
  relay_list_endpoints returns type ("dispatch"|"query"|"persistent"|"agent"|"unknown") and expiresAt
77601
77642
  (ISO string or null) for each endpoint. Use these to identify active inboxes and their expiry.
@@ -77810,7 +77851,7 @@ var CORE_TOOLS = [
77810
77851
  "mcp__dorkos__ping",
77811
77852
  "mcp__dorkos__get_server_info",
77812
77853
  "mcp__dorkos__get_session_count",
77813
- "mcp__dorkos__get_current_agent"
77854
+ "mcp__dorkos__get_agent"
77814
77855
  ];
77815
77856
  var PULSE_TOOLS = [
77816
77857
  "mcp__dorkos__pulse_list_schedules",
@@ -77824,8 +77865,8 @@ var RELAY_TOOLS = [
77824
77865
  "mcp__dorkos__relay_inbox",
77825
77866
  "mcp__dorkos__relay_list_endpoints",
77826
77867
  "mcp__dorkos__relay_register_endpoint",
77827
- "mcp__dorkos__relay_query",
77828
- "mcp__dorkos__relay_dispatch",
77868
+ "mcp__dorkos__relay_send_and_wait",
77869
+ "mcp__dorkos__relay_send_async",
77829
77870
  // NEW
77830
77871
  "mcp__dorkos__relay_unregister_endpoint"
77831
77872
  // NEW
@@ -77851,10 +77892,7 @@ var BINDING_TOOLS = [
77851
77892
  "mcp__dorkos__binding_create",
77852
77893
  "mcp__dorkos__binding_delete"
77853
77894
  ];
77854
- var TRACE_TOOLS = [
77855
- "mcp__dorkos__relay_get_trace",
77856
- "mcp__dorkos__relay_get_metrics"
77857
- ];
77895
+ var TRACE_TOOLS = ["mcp__dorkos__relay_get_trace", "mcp__dorkos__relay_get_metrics"];
77858
77896
  function resolveToolConfig(agentConfig, deps) {
77859
77897
  const agent = agentConfig ?? {};
77860
77898
  return {
@@ -77932,7 +77970,11 @@ async function* executeSdkQuery(sessionId, content3, session, opts, messageOpts,
77932
77970
  pulseEnabled: isPulseEnabled(),
77933
77971
  globalConfig
77934
77972
  });
77935
- 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
+ );
77936
77978
  const systemPromptAppend = messageOpts?.systemPromptAppend ? `${baseAppend}
77937
77979
 
77938
77980
  ${messageOpts.systemPromptAppend}` : baseAppend;
@@ -77951,9 +77993,12 @@ ${messageOpts.systemPromptAppend}` : baseAppend;
77951
77993
  if (session.hasStarted) {
77952
77994
  sdkOptions.resume = session.sdkSessionId;
77953
77995
  if (session.sdkSessionId === sessionId) {
77954
- logger.debug("[sendMessage] resuming with sdkSessionId === sessionId (expected after server restart)", {
77955
- session: sessionId
77956
- });
77996
+ logger.debug(
77997
+ "[sendMessage] resuming with sdkSessionId === sessionId (expected after server restart)",
77998
+ {
77999
+ session: sessionId
78000
+ }
78001
+ );
77957
78002
  }
77958
78003
  }
77959
78004
  const cwdSource = messageOpts?.cwd ? "opts.cwd" : opts.sessionCwd ? "session.cwd" : "default";
@@ -78340,32 +78385,41 @@ var ClaudeCodeRuntime = class _ClaudeCodeRuntime {
78340
78385
  }
78341
78386
  }
78342
78387
  const session = this.sessions.get(sessionId);
78343
- yield* executeSdkQuery(sessionId, content3, session, {
78344
- cwd: this.cwd,
78345
- sessionCwd: session.cwd,
78346
- claudeCliPath: this.claudeCliPath,
78347
- meshCore: this.meshCore,
78348
- mcpServerFactory: this.mcpServerFactory,
78349
- onModelsReceived: !this.cachedModels ? (models) => {
78350
- this.cachedModels = models;
78351
- logger.debug("[sendMessage] cached supported models", {
78352
- count: models.length
78353
- });
78354
- } : void 0,
78355
- onMcpStatusReceived: (servers) => {
78356
- const key = opts?.cwd || session.cwd || this.cwd;
78357
- this.cachedMcpStatus.set(key, servers);
78358
- logger.debug("[sendMessage] cached MCP server status", { cwd: key, count: servers.length });
78359
- },
78360
- onCommandsReceived: !this.cachedSdkCommands ? (commands) => {
78361
- this.cachedSdkCommands = commands;
78362
- logger.debug("[sendMessage] cached supported commands", {
78363
- count: commands.length
78364
- });
78365
- } : void 0,
78366
- sdkSessionIndex: this.sdkSessionIndex,
78367
- sessionMapKey: sessionId
78368
- }, 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
+ );
78369
78423
  }
78370
78424
  // ---------------------------------------------------------------------------
78371
78425
  // Interactive flows
@@ -78616,6 +78670,25 @@ function jsonContent(data, isError2 = false) {
78616
78670
  }
78617
78671
 
78618
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
+ }
78619
78692
  async function handlePing() {
78620
78693
  return {
78621
78694
  content: [
@@ -78649,16 +78722,18 @@ async function handleGetServerInfo(args) {
78649
78722
  };
78650
78723
  }
78651
78724
  function createGetSessionCountHandler(deps) {
78652
- return async function handleGetSessionCount() {
78725
+ return async function handleGetSessionCount(args) {
78653
78726
  try {
78654
- const sessions = await deps.transcriptReader.listSessions(deps.defaultCwd);
78727
+ const resolvedCwd = resolveAgentCwd(deps, args);
78728
+ const sessions = await deps.transcriptReader.listSessions(resolvedCwd);
78655
78729
  return {
78656
78730
  content: [
78657
78731
  {
78658
78732
  type: "text",
78659
78733
  text: JSON.stringify({
78660
78734
  count: sessions.length,
78661
- cwd: deps.defaultCwd
78735
+ cwd: resolvedCwd,
78736
+ ...args.agent_id && { agent_id: args.agent_id }
78662
78737
  })
78663
78738
  }
78664
78739
  ]
@@ -78678,12 +78753,16 @@ function createGetSessionCountHandler(deps) {
78678
78753
  }
78679
78754
  };
78680
78755
  }
78681
- function createGetCurrentAgentHandler(deps) {
78682
- return async () => {
78756
+ function createGetAgentHandler(deps) {
78757
+ return async (args) => {
78683
78758
  try {
78684
- const manifest = await readManifest(deps.defaultCwd);
78759
+ const resolvedCwd = resolveAgentCwd(deps, args);
78760
+ const manifest = await readManifest(resolvedCwd);
78685
78761
  if (!manifest) {
78686
- 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
+ });
78687
78766
  }
78688
78767
  return jsonContent({ agent: manifest });
78689
78768
  } catch (err) {
@@ -78694,9 +78773,13 @@ function createGetCurrentAgentHandler(deps) {
78694
78773
  }
78695
78774
  };
78696
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
+ };
78697
78780
  function getCoreTools(deps) {
78698
78781
  const handleGetSessionCount = createGetSessionCountHandler(deps);
78699
- const handleGetCurrentAgent = createGetCurrentAgentHandler(deps);
78782
+ const handleGetAgent = createGetAgentHandler(deps);
78700
78783
  return [
78701
78784
  tool(
78702
78785
  "ping",
@@ -78712,15 +78795,15 @@ function getCoreTools(deps) {
78712
78795
  ),
78713
78796
  tool(
78714
78797
  "get_session_count",
78715
- "Returns the number of sessions visible in the SDK transcript directory.",
78716
- {},
78798
+ "Returns the number of sessions for a specific agent. Provide either agent_id (ULID) or cwd (working directory path).",
78799
+ agentScopeSchema,
78717
78800
  handleGetSessionCount
78718
78801
  ),
78719
78802
  tool(
78720
- "get_current_agent",
78721
- "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.",
78722
- {},
78723
- 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
78724
78807
  )
78725
78808
  ];
78726
78809
  }
@@ -78759,7 +78842,10 @@ function createCreateScheduleHandler(deps) {
78759
78842
  });
78760
78843
  deps.pulseStore.updateSchedule(schedule.id, { status: "pending_approval" });
78761
78844
  const updated = deps.pulseStore.getSchedule(schedule.id);
78762
- 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
+ });
78763
78849
  };
78764
78850
  }
78765
78851
  function createUpdateScheduleHandler(deps) {
@@ -78879,7 +78965,11 @@ function createRelaySendHandler(deps) {
78879
78965
  replyTo: args.replyTo,
78880
78966
  budget: args.budget
78881
78967
  });
78882
- 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
+ });
78883
78973
  } catch (e2) {
78884
78974
  const message = e2 instanceof Error ? e2.message : "Publish failed";
78885
78975
  const code3 = message.includes("Access denied") ? "ACCESS_DENIED" : message.includes("Invalid subject") ? "INVALID_SUBJECT" : "PUBLISH_FAILED";
@@ -78963,7 +79053,10 @@ function createRelayQueryHandler(deps) {
78963
79053
  });
78964
79054
  if (result2.deliveredTo === 0 && result2.rejected && result2.rejected.length > 0) {
78965
79055
  const reason = result2.rejected[0]?.reason ?? "unknown";
78966
- return jsonContent({ error: `Message rejected: ${reason}`, code: "REJECTED", reason }, true);
79056
+ return jsonContent(
79057
+ { error: `Message rejected: ${reason}`, code: "REJECTED", reason },
79058
+ true
79059
+ );
78967
79060
  }
78968
79061
  sentMessageId = result2.messageId;
78969
79062
  } catch (e2) {
@@ -78978,7 +79071,9 @@ function createRelayQueryHandler(deps) {
78978
79071
  };
78979
79072
  const timer = setTimeout(() => {
78980
79073
  cleanup();
78981
- 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
+ );
78982
79077
  }, timeoutMs);
78983
79078
  const unsub = relay.subscribe(inboxSubject, (envelope) => {
78984
79079
  const payload = envelope.payload;
@@ -79056,7 +79151,10 @@ function createRelayUnregisterEndpointHandler(deps) {
79056
79151
  try {
79057
79152
  const removed = await deps.relayCore.unregisterEndpoint(args.subject);
79058
79153
  if (!removed) {
79059
- 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
+ );
79060
79158
  }
79061
79159
  return jsonContent({ success: true, subject: args.subject });
79062
79160
  } catch (e2) {
@@ -79111,13 +79209,15 @@ function getRelayTools(deps) {
79111
79209
  createRelayRegisterEndpointHandler(deps)
79112
79210
  ),
79113
79211
  tool3(
79114
- "relay_query",
79212
+ "relay_send_and_wait",
79115
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.',
79116
79214
  {
79117
79215
  to_subject: z18.string().describe('Target subject for the message (e.g., "relay.agent.{agentId}")'),
79118
79216
  payload: z18.unknown().describe("Message payload (any JSON-serializable value)"),
79119
79217
  from: z18.string().describe("Sender subject identifier"),
79120
- 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
+ ),
79121
79221
  budget: z18.object({
79122
79222
  maxHops: z18.number().int().min(1).optional().describe("Max hop count"),
79123
79223
  ttl: z18.number().int().optional().describe("Unix timestamp (ms) expiry"),
@@ -79127,8 +79227,8 @@ function getRelayTools(deps) {
79127
79227
  createRelayQueryHandler(deps)
79128
79228
  ),
79129
79229
  tool3(
79130
- "relay_dispatch",
79131
- "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.",
79132
79232
  {
79133
79233
  to_subject: z18.string().describe('Target subject (e.g., "relay.agent.{agentId}")'),
79134
79234
  payload: z18.unknown().describe("Message payload"),
@@ -79143,7 +79243,7 @@ function getRelayTools(deps) {
79143
79243
  ),
79144
79244
  tool3(
79145
79245
  "relay_unregister_endpoint",
79146
- "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).",
79147
79247
  {
79148
79248
  subject: z18.string().describe("Subject of the endpoint to unregister")
79149
79249
  },
@@ -79157,7 +79257,10 @@ import { tool as tool4 } from "@anthropic-ai/claude-agent-sdk";
79157
79257
  import { z as z19 } from "zod";
79158
79258
  function requireAdapterManager(deps) {
79159
79259
  if (!deps.adapterManager) {
79160
- 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
+ );
79161
79264
  }
79162
79265
  return null;
79163
79266
  }
@@ -79244,7 +79347,10 @@ import { tool as tool5 } from "@anthropic-ai/claude-agent-sdk";
79244
79347
  import { z as z20 } from "zod";
79245
79348
  function requireBindingStore(deps) {
79246
79349
  if (!deps.bindingStore) {
79247
- 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
+ );
79248
79354
  }
79249
79355
  return null;
79250
79356
  }
@@ -79289,12 +79395,7 @@ function createBindingDeleteHandler(deps) {
79289
79395
  function getBindingTools(deps) {
79290
79396
  if (!deps.bindingStore) return [];
79291
79397
  return [
79292
- tool5(
79293
- "binding_list",
79294
- "List all adapter-to-agent bindings.",
79295
- {},
79296
- createBindingListHandler(deps)
79297
- ),
79398
+ tool5("binding_list", "List all adapter-to-agent bindings.", {}, createBindingListHandler(deps)),
79298
79399
  tool5(
79299
79400
  "binding_create",
79300
79401
  "Create a new adapter-to-agent binding. Maps an external adapter to a specific agent directory.",
@@ -79379,14 +79480,24 @@ function createMeshDiscoverHandler(deps) {
79379
79480
  if (err) return err;
79380
79481
  try {
79381
79482
  const candidates = [];
79483
+ const autoImported = [];
79382
79484
  for await (const event of deps.meshCore.discover(args.roots, {
79383
79485
  maxDepth: args.maxDepth
79384
79486
  })) {
79385
79487
  if (event.type === "candidate") {
79386
79488
  candidates.push(event.data);
79489
+ } else if (event.type === "auto-import" && args.includeRegistered) {
79490
+ autoImported.push(event.data);
79387
79491
  }
79388
79492
  }
79389
- 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
+ });
79390
79501
  } catch (e2) {
79391
79502
  const message = e2 instanceof Error ? e2.message : "Discovery failed";
79392
79503
  return jsonContent({ error: message, code: "DISCOVER_FAILED" }, true);
@@ -79398,11 +79509,6 @@ function createMeshRegisterHandler(deps) {
79398
79509
  const err = requireMesh(deps);
79399
79510
  if (err) return err;
79400
79511
  try {
79401
- const overrides = {};
79402
- if (args.name) overrides.name = args.name;
79403
- if (args.description) overrides.description = args.description;
79404
- if (args.runtime) overrides.runtime = args.runtime;
79405
- if (args.capabilities) overrides.capabilities = args.capabilities;
79406
79512
  const agent = await deps.meshCore.registerByPath(
79407
79513
  args.path,
79408
79514
  {
@@ -79479,7 +79585,10 @@ function createMeshInspectHandler(deps) {
79479
79585
  if (err) return err;
79480
79586
  const result2 = deps.meshCore.inspect(args.agentId);
79481
79587
  if (!result2) {
79482
- 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
+ };
79483
79592
  }
79484
79593
  return jsonContent(result2);
79485
79594
  };
@@ -79497,10 +79606,13 @@ function getMeshTools(deps) {
79497
79606
  return [
79498
79607
  tool7(
79499
79608
  "mesh_discover",
79500
- "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.",
79501
79610
  {
79502
79611
  roots: z22.array(z22.string()).describe("Root directories to scan for agents"),
79503
- 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
+ )
79504
79616
  },
79505
79617
  createMeshDiscoverHandler(deps)
79506
79618
  ),
@@ -84981,7 +85093,9 @@ var PulseStore = class {
84981
85093
  conditions.push(eq(pulseRuns.scheduleId, opts.scheduleId));
84982
85094
  }
84983
85095
  if (opts.status) {
84984
- conditions.push(eq(pulseRuns.status, opts.status));
85096
+ conditions.push(
85097
+ eq(pulseRuns.status, opts.status)
85098
+ );
84985
85099
  }
84986
85100
  const query2 = this.db.select().from(pulseRuns).orderBy(desc(pulseRuns.createdAt)).limit(limit).offset(offset);
84987
85101
  if (conditions.length > 0) {
@@ -85953,7 +86067,9 @@ var SchedulerService = class {
85953
86067
  this.store.updateRun(run.id, {
85954
86068
  status: "running"
85955
86069
  });
85956
- 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
+ );
85957
86073
  }
85958
86074
  }
85959
86075
  /** Execute a run directly via AgentManager — manages AbortController, streams output, updates status. */
@@ -86110,13 +86226,9 @@ async function loadPresets(dorkHome) {
86110
86226
  }
86111
86227
 
86112
86228
  // ../../apps/server/src/routes/pulse.ts
86113
- function createPulseRouter(store, scheduler, meshCore2) {
86229
+ function createPulseRouter(store, scheduler, dorkHome, meshCore2) {
86114
86230
  const router13 = Router14();
86115
86231
  router13.get("/presets", async (_req, res) => {
86116
- const dorkHome = env.DORK_HOME;
86117
- if (!dorkHome) {
86118
- return res.status(500).json({ error: "DORK_HOME not configured" });
86119
- }
86120
86232
  const presets = await loadPresets(dorkHome);
86121
86233
  return res.json(presets);
86122
86234
  });
@@ -86224,7 +86336,6 @@ import * as os5 from "node:os";
86224
86336
  import fs14 from "node:fs";
86225
86337
 
86226
86338
  // ../relay/dist/endpoint-registry.js
86227
- import { createHash } from "node:crypto";
86228
86339
  import { mkdir as mkdir2, rm } from "node:fs/promises";
86229
86340
  import { join as join4 } from "node:path";
86230
86341
 
@@ -86316,10 +86427,6 @@ function matchTokens(subject, pattern, si, pi) {
86316
86427
 
86317
86428
  // ../relay/dist/endpoint-registry.js
86318
86429
  var MAILDIR_DIRS = ["tmp", "new", "cur", "failed"];
86319
- var HASH_LENGTH = 12;
86320
- function hashSubject(subject) {
86321
- return createHash("sha256").update(subject).digest("hex").slice(0, HASH_LENGTH);
86322
- }
86323
86430
  var EndpointRegistry = class {
86324
86431
  /** Base directory for all endpoint mailboxes (e.g. `~/.dork/relay/mailboxes`). */
86325
86432
  mailboxesDir;
@@ -86337,8 +86444,8 @@ var EndpointRegistry = class {
86337
86444
  /**
86338
86445
  * Register a new message endpoint.
86339
86446
  *
86340
- * Validates the subject, computes a deterministic hash, creates the
86341
- * 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.
86342
86449
  *
86343
86450
  * @param subject - The hierarchical subject for this endpoint (e.g. `relay.agent.myproject.backend`).
86344
86451
  * Must not contain wildcards (`*` or `>`).
@@ -86356,14 +86463,13 @@ var EndpointRegistry = class {
86356
86463
  if (this.endpoints.has(subject)) {
86357
86464
  throw new Error(`Endpoint already registered: ${subject}`);
86358
86465
  }
86359
- const hash = hashSubject(subject);
86360
- const maildirPath = join4(this.mailboxesDir, hash);
86466
+ const maildirPath = join4(this.mailboxesDir, subject);
86361
86467
  for (const dir of MAILDIR_DIRS) {
86362
86468
  await mkdir2(join4(maildirPath, dir), { recursive: true });
86363
86469
  }
86364
86470
  const info = {
86365
86471
  subject,
86366
- hash,
86472
+ hash: subject,
86367
86473
  maildirPath,
86368
86474
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
86369
86475
  };
@@ -88151,11 +88257,10 @@ var AdapterDelivery = class _AdapterDelivery {
88151
88257
  })
88152
88258
  ]);
88153
88259
  if (result2 && result2.success) {
88154
- const subjectHash = hashSubject(subject);
88155
88260
  this.sqliteIndex.insertMessage({
88156
88261
  id: envelope.id,
88157
88262
  subject,
88158
- endpointHash: `adapter:${subjectHash}`,
88263
+ endpointHash: `adapter:${subject}`,
88159
88264
  status: "delivered",
88160
88265
  createdAt: envelope.createdAt,
88161
88266
  expiresAt: null
@@ -88466,10 +88571,9 @@ var RelayPublishPipeline = class {
88466
88571
  }
88467
88572
  /** Dead-letter a message that had no delivery targets. */
88468
88573
  async deadLetter(subject, envelope, adapterResult) {
88469
- const subjectHash = hashSubject(subject);
88470
- await this.deps.maildirStore.ensureMaildir(subjectHash);
88574
+ await this.deps.maildirStore.ensureMaildir(subject);
88471
88575
  const reason = adapterResult?.error ? `adapter delivery failed: ${adapterResult.error}` : "no matching endpoints or adapters";
88472
- await this.deps.deadLetterQueue.reject(subjectHash, envelope, reason);
88576
+ await this.deps.deadLetterQueue.reject(subject, envelope, reason);
88473
88577
  }
88474
88578
  /** Record a trace span for delivery tracking (best-effort). */
88475
88579
  recordTrace(messageId, subject, deliveredTo, rejected, adapterResult, envelope) {
@@ -89046,6 +89150,7 @@ var BaseRelayAdapter = class {
89046
89150
  };
89047
89151
 
89048
89152
  // ../relay/dist/adapter-registry.js
89153
+ var ADAPTER_START_TIMEOUT_MS = 3e4;
89049
89154
  var AdapterRegistry = class {
89050
89155
  adapters = /* @__PURE__ */ new Map();
89051
89156
  relay = null;
@@ -89082,7 +89187,19 @@ var AdapterRegistry = class {
89082
89187
  throw new Error("AdapterRegistry: relay not set \u2014 call setRelay() before registering adapters");
89083
89188
  }
89084
89189
  const existing = this.adapters.get(adapter.id);
89085
- 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`);
89086
89203
  this.adapters.set(adapter.id, adapter);
89087
89204
  if (existing) {
89088
89205
  try {
@@ -101978,12 +102095,18 @@ var import_grammy = __toESM(require_mod2(), 1);
101978
102095
  import crypto4 from "node:crypto";
101979
102096
  import { createServer } from "node:http";
101980
102097
  var DEFAULT_WEBHOOK_PORT = 8443;
101981
- async function startWebhookMode(bot, adapterId, webhookUrl, webhookPort, webhookSecret) {
102098
+ async function startWebhookMode(bot, adapterId, webhookUrl, webhookPort, webhookSecret, timeoutMs = 15e3) {
101982
102099
  if (!webhookUrl) {
101983
102100
  throw new Error(`TelegramAdapter(${adapterId}): webhookUrl is required when mode is 'webhook'`);
101984
102101
  }
101985
102102
  const secret = webhookSecret ?? crypto4.randomUUID();
101986
- 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));
101987
102110
  const port = webhookPort ?? DEFAULT_WEBHOOK_PORT;
101988
102111
  const handler = (0, import_grammy.webhookCallback)(bot, "http", { secretToken: secret });
101989
102112
  const server = createServer(handler);
@@ -102116,6 +102239,8 @@ For local development, use a tunnel service (e.g., ngrok, Cloudflare Tunnel).`
102116
102239
  setupInstructions: "Open Telegram and search for @BotFather. Send /newbot, choose a name and username. Copy the token provided."
102117
102240
  };
102118
102241
  var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102242
+ /** Timeout for bot.init() and setWebhook() calls (ms). */
102243
+ static INIT_TIMEOUT_MS = 15e3;
102119
102244
  /** Reconnection delay schedule (ms) -- exponential backoff. */
102120
102245
  static RECONNECT_DELAYS = [5e3, 1e4, 3e4, 6e4, 6e4];
102121
102246
  config;
@@ -102135,7 +102260,7 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102135
102260
  async testConnection() {
102136
102261
  try {
102137
102262
  const bot = new import_grammy2.Bot(this.config.token);
102138
- await bot.init();
102263
+ await this.initBotWithTimeout(bot);
102139
102264
  return { ok: true, botUsername: bot.botInfo.username };
102140
102265
  } catch (err) {
102141
102266
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -102185,7 +102310,11 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102185
102310
  void handleTypingSignal(this.bot, subject, this.outboundState, signal.state);
102186
102311
  });
102187
102312
  if (this.config.mode === "webhook") {
102188
- 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);
102189
102318
  } else {
102190
102319
  await this.startPollingMode(bot);
102191
102320
  }
@@ -102240,9 +102369,26 @@ var TelegramAdapter = class _TelegramAdapter extends BaseRelayAdapter {
102240
102369
  });
102241
102370
  }
102242
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
+ }
102243
102387
  /** Start grammy bot in long-polling mode with eager token validation. */
102244
102388
  async startPollingMode(bot) {
102245
- 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");
102246
102392
  bot.start({
102247
102393
  drop_pending_updates: true,
102248
102394
  onStart: () => {
@@ -102385,6 +102531,7 @@ var WebhookAdapter = class extends BaseRelayAdapter {
102385
102531
  * @param _relay - The RelayPublisher (stored by base class; unused here)
102386
102532
  */
102387
102533
  async _start(_relay) {
102534
+ this.logger.info("webhook adapter ready", { subject: this.config.inbound.subject });
102388
102535
  this.nonceInterval = setInterval(() => {
102389
102536
  this.pruneExpiredNonces();
102390
102537
  }, NONCE_PRUNE_INTERVAL_MS);
@@ -102904,7 +103051,11 @@ async function handleTextDelta(textChunk, streaming, nativeStreaming, ctx) {
102904
103051
  return { success: true, durationMs: now - startTime };
102905
103052
  } catch (err) {
102906
103053
  callbacks.recordError(err);
102907
- 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
+ };
102908
103059
  }
102909
103060
  }
102910
103061
  async function flushStreamBuffer(ctx) {
@@ -103100,7 +103251,10 @@ ${inputPreview}
103100
103251
  blocks: [
103101
103252
  {
103102
103253
  type: "section",
103103
- 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
+ }
103104
103258
  }
103105
103259
  ]
103106
103260
  });
@@ -103149,7 +103303,11 @@ async function deliverMessage2(opts) {
103149
103303
  return { success: true, durationMs: Date.now() - startTime };
103150
103304
  }
103151
103305
  if (!client) {
103152
- 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
+ };
103153
103311
  }
103154
103312
  const channelId = extractChannelId(subject);
103155
103313
  if (!channelId) {
@@ -103203,7 +103361,11 @@ async function deliverMessage2(opts) {
103203
103361
  }
103204
103362
  const text6 = truncateText(formatForPlatform(extractPayloadContent(envelope.payload), "slack"), MAX_MESSAGE_LENGTH2);
103205
103363
  logger3.debug(`deliver: standard payload to ${channelId} (${text6.length} chars)`);
103206
- 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);
103207
103369
  }
103208
103370
 
103209
103371
  // ../relay/dist/adapters/slack/slack-adapter.js
@@ -103265,7 +103427,14 @@ var SLACK_MANIFEST = {
103265
103427
  stepId: "create-app",
103266
103428
  title: "Create & Configure a Slack App",
103267
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.',
103268
- fields: ["botToken", "appToken", "signingSecret", "streaming", "nativeStreaming", "typingIndicator"]
103430
+ fields: [
103431
+ "botToken",
103432
+ "appToken",
103433
+ "signingSecret",
103434
+ "streaming",
103435
+ "nativeStreaming",
103436
+ "typingIndicator"
103437
+ ]
103269
103438
  }
103270
103439
  ],
103271
103440
  configFields: [
@@ -103349,7 +103518,9 @@ var SLACK_MANIFEST = {
103349
103518
  ],
103350
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.'
103351
103520
  };
103352
- 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;
103353
103524
  config;
103354
103525
  app = null;
103355
103526
  /** Bot's own user ID — cached after auth.test for echo prevention. */
@@ -103372,7 +103543,7 @@ var SlackAdapter = class extends BaseRelayAdapter {
103372
103543
  try {
103373
103544
  const { WebClient } = await Promise.resolve().then(() => __toESM(require_dist4(), 1));
103374
103545
  const tempClient = new WebClient(this.config.botToken);
103375
- const result2 = await tempClient.auth.test();
103546
+ const result2 = await _SlackAdapter.withInitTimeout(tempClient.auth.test());
103376
103547
  return { ok: true, botUsername: result2.user };
103377
103548
  } catch (err) {
103378
103549
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
@@ -103387,8 +103558,12 @@ var SlackAdapter = class extends BaseRelayAdapter {
103387
103558
  socketMode: true,
103388
103559
  logLevel: import_bolt.LogLevel.WARN
103389
103560
  });
103390
- const authResult = await app.client.auth.test();
103561
+ const authResult = await _SlackAdapter.withInitTimeout(app.client.auth.test());
103391
103562
  this.botUserId = authResult.user_id ?? "";
103563
+ this.logger.info("authenticated", {
103564
+ botUserId: this.botUserId,
103565
+ workspace: authResult.team
103566
+ });
103392
103567
  app.message(async ({ event, client }) => {
103393
103568
  await handleInboundMessage2(event, client, relay, this.botUserId, this.makeInboundCallbacks(), this.logger, this.config.typingIndicator ?? "none", this.pendingReactions);
103394
103569
  });
@@ -103406,6 +103581,7 @@ var SlackAdapter = class extends BaseRelayAdapter {
103406
103581
  app.error(async (error) => {
103407
103582
  this.recordError(error);
103408
103583
  });
103584
+ this.logger.info("connecting via Socket Mode");
103409
103585
  await app.start();
103410
103586
  this.app = app;
103411
103587
  }
@@ -103450,6 +103626,21 @@ var SlackAdapter = class extends BaseRelayAdapter {
103450
103626
  logger: this.logger
103451
103627
  });
103452
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
+ }
103453
103644
  /**
103454
103645
  * Handle a tool approval or denial action from Slack interactive buttons.
103455
103646
  *
@@ -103582,7 +103773,11 @@ var STREAM_EVENT_TYPES = /* @__PURE__ */ new Set([
103582
103773
  async function handleAgentMessage(subject, envelope, context, startTime, config, deps, relay) {
103583
103774
  const agentId = extractAgentId(subject);
103584
103775
  if (!agentId) {
103585
- 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
+ };
103586
103781
  }
103587
103782
  const log = deps.logger ?? console;
103588
103783
  if (!deps.agentSessionStore) {
@@ -103674,7 +103869,11 @@ async function handleAgentMessage(subject, envelope, context, startTime, config,
103674
103869
  } catch (err) {
103675
103870
  streamError = err instanceof Error ? err.message : String(err);
103676
103871
  log.error("[CCA] Streaming error:", err);
103677
- 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
+ });
103678
103877
  } finally {
103679
103878
  clearTimeout(timeout);
103680
103879
  if (!streamedDone && envelope.replyTo && relay) {
@@ -104343,11 +104542,7 @@ async function loadAdapterConfig(configPath) {
104343
104542
  async function saveAdapterConfig(configPath, configs) {
104344
104543
  await mkdir4(dirname3(configPath), { recursive: true });
104345
104544
  const tmpPath = `${configPath}.tmp`;
104346
- await writeFile2(
104347
- tmpPath,
104348
- JSON.stringify({ adapters: configs }, null, 2),
104349
- "utf-8"
104350
- );
104545
+ await writeFile2(tmpPath, JSON.stringify({ adapters: configs }, null, 2), "utf-8");
104351
104546
  await rename2(tmpPath, configPath);
104352
104547
  }
104353
104548
  async function ensureDefaultAdapterConfig(configPath) {
@@ -104371,11 +104566,7 @@ async function ensureDefaultAdapterConfig(configPath) {
104371
104566
  };
104372
104567
  try {
104373
104568
  await mkdir4(dirname3(configPath), { recursive: true });
104374
- await writeFile2(
104375
- configPath,
104376
- JSON.stringify(defaultConfig, null, 2),
104377
- "utf-8"
104378
- );
104569
+ await writeFile2(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
104379
104570
  logger.info("[AdapterConfig] Generated default adapters.json with claude-code adapter");
104380
104571
  } catch (writeErr) {
104381
104572
  logger.warn("[AdapterConfig] Failed to write default config:", writeErr);
@@ -104465,38 +104656,25 @@ function defaultAdapterStatus() {
104465
104656
  async function createAdapter(config, deps, configPath, onPluginManifest) {
104466
104657
  switch (config.type) {
104467
104658
  case "telegram": {
104468
- const adapter = new TelegramAdapter(
104469
- config.id,
104470
- config.config
104471
- );
104659
+ const adapter = new TelegramAdapter(config.id, config.config);
104472
104660
  adapter.setLogger(createTaggedLogger(`telegram:${config.id}`));
104473
104661
  return adapter;
104474
104662
  }
104475
104663
  case "webhook":
104476
- return new WebhookAdapter(
104477
- config.id,
104478
- config.config
104479
- );
104664
+ return new WebhookAdapter(config.id, config.config);
104480
104665
  case "slack": {
104481
- const adapter = new SlackAdapter(
104482
- config.id,
104483
- config.config
104484
- );
104666
+ const adapter = new SlackAdapter(config.id, config.config);
104485
104667
  adapter.setLogger(createTaggedLogger(`slack:${config.id}`));
104486
104668
  return adapter;
104487
104669
  }
104488
104670
  case "claude-code":
104489
- return new ClaudeCodeAdapter(
104490
- config.id,
104491
- config.config,
104492
- {
104493
- agentManager: deps.agentManager,
104494
- traceStore: deps.traceStore,
104495
- pulseStore: deps.pulseStore,
104496
- agentSessionStore: deps.agentSessionStore,
104497
- logger
104498
- }
104499
- );
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
+ });
104500
104678
  case "plugin":
104501
104679
  return loadPluginAdapter(config, configPath, onPluginManifest);
104502
104680
  default:
@@ -104862,7 +105040,10 @@ var AgentSessionStore = class {
104862
105040
  }
104863
105041
  /** Enqueue an atomic persist, serialized to prevent concurrent tmp+rename races. */
104864
105042
  persist() {
104865
- this.writeLock = this.writeLock.then(() => this.doPersist(), () => this.doPersist());
105043
+ this.writeLock = this.writeLock.then(
105044
+ () => this.doPersist(),
105045
+ () => this.doPersist()
105046
+ );
104866
105047
  return this.writeLock;
104867
105048
  }
104868
105049
  /** Atomic tmp+rename write. Must be serialized via writeLock. */
@@ -104928,7 +105109,10 @@ var BindingRouter = class _BindingRouter {
104928
105109
  try {
104929
105110
  await this.saveSessionMap();
104930
105111
  } catch (err) {
104931
- 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
+ );
104932
105116
  }
104933
105117
  logger.info(`Cleaned up ${removed} orphaned session mapping(s)`);
104934
105118
  }
@@ -104946,9 +105130,7 @@ var BindingRouter = class _BindingRouter {
104946
105130
  }
104947
105131
  const binding = this.deps.bindingStore.resolve(adapterId, chatId, channelType);
104948
105132
  if (!binding) {
104949
- logger.info(
104950
- `BindingRouter: no binding for adapter=${adapterId} chat=${chatId}, skipping`
104951
- );
105133
+ logger.info(`BindingRouter: no binding for adapter=${adapterId} chat=${chatId}, skipping`);
104952
105134
  return;
104953
105135
  }
104954
105136
  if (binding.canReceive === false) {
@@ -105024,7 +105206,10 @@ var BindingRouter = class _BindingRouter {
105024
105206
  try {
105025
105207
  await this.saveSessionMap();
105026
105208
  } catch (err) {
105027
- 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
+ );
105028
105213
  }
105029
105214
  return sessionId;
105030
105215
  } finally {
@@ -105060,10 +105245,7 @@ var BindingRouter = class _BindingRouter {
105060
105245
  agentId: binding.agentId,
105061
105246
  projectPath
105062
105247
  });
105063
- const session = await this.deps.agentManager.createSession(
105064
- projectPath,
105065
- binding.permissionMode
105066
- );
105248
+ const session = await this.deps.agentManager.createSession(projectPath, binding.permissionMode);
105067
105249
  return session.id;
105068
105250
  }
105069
105251
  /**
@@ -105123,7 +105305,10 @@ var BindingRouter = class _BindingRouter {
105123
105305
  }
105124
105306
  }
105125
105307
  saveSessionMap() {
105126
- this.writeLock = this.writeLock.then(() => this.doSaveSessionMap(), () => this.doSaveSessionMap());
105308
+ this.writeLock = this.writeLock.then(
105309
+ () => this.doSaveSessionMap(),
105310
+ () => this.doSaveSessionMap()
105311
+ );
105127
105312
  return this.writeLock;
105128
105313
  }
105129
105314
  /** Atomic tmp+rename write of the session map. Must be serialized via writeLock. */
@@ -105256,7 +105441,9 @@ var AdapterManager = class {
105256
105441
  /** Initialize the binding subsystem. Non-fatal on failure — logs and continues. */
105257
105442
  async initBindingSubsystem() {
105258
105443
  if (!this.deps.relayCore || !this.deps.meshCore) {
105259
- 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
+ );
105260
105447
  return;
105261
105448
  }
105262
105449
  this.bindingSubsystem = await BindingSubsystem.init({
@@ -105316,7 +105503,11 @@ var AdapterManager = class {
105316
105503
  config.enabled = false;
105317
105504
  await saveAdapterConfig(this.configPath, this.configs);
105318
105505
  await this.registry.unregister(id);
105319
- 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
+ );
105320
105511
  }
105321
105512
  /**
105322
105513
  * List all adapter configs paired with their current runtime status.
@@ -105342,10 +105533,7 @@ var AdapterManager = class {
105342
105533
  };
105343
105534
  const maskedConfig = {
105344
105535
  ...config,
105345
- config: maskSensitiveFields(
105346
- config.config,
105347
- manifest
105348
- )
105536
+ config: maskSensitiveFields(config.config, manifest)
105349
105537
  };
105350
105538
  return { config: maskedConfig, status };
105351
105539
  }
@@ -105401,6 +105589,7 @@ var AdapterManager = class {
105401
105589
  }
105402
105590
  /** Add a new adapter instance, persist config, and start it if enabled. */
105403
105591
  async addAdapter(type, id, config, enabled = true, label) {
105592
+ logger.info("[AdapterManager] adding adapter", { type, id, enabled });
105404
105593
  if (this.configs.some((c3) => c3.id === id)) {
105405
105594
  throw new AdapterError(`Adapter with ID '${id}' already exists`, "DUPLICATE_ID");
105406
105595
  }
@@ -105427,10 +105616,25 @@ var AdapterManager = class {
105427
105616
  };
105428
105617
  this.configs.push(adapterConfig);
105429
105618
  await saveAdapterConfig(this.configPath, this.configs);
105619
+ logger.debug("[AdapterManager] config saved", { id });
105430
105620
  if (enabled) {
105431
105621
  const adapter = await this.buildAdapter(adapterConfig);
105432
105622
  if (adapter) {
105433
- 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
+ }
105434
105638
  }
105435
105639
  }
105436
105640
  }
@@ -105603,10 +105807,7 @@ var AdapterManager = class {
105603
105807
  if (manifest.setupGuide) continue;
105604
105808
  try {
105605
105809
  const docsPath = this.resolveAdapterDocsPath(type);
105606
- const setupGuide = await readFile8(
105607
- join12(docsPath, "setup.md"),
105608
- "utf-8"
105609
- );
105810
+ const setupGuide = await readFile8(join12(docsPath, "setup.md"), "utf-8");
105610
105811
  this.manifests.set(type, { ...manifest, setupGuide });
105611
105812
  } catch {
105612
105813
  }
@@ -105923,7 +106124,10 @@ function createRelayRouter(relayCore2, adapterManager2, traceStore2) {
105923
106124
  return res.json(publishResult);
105924
106125
  } catch (err) {
105925
106126
  const message = err instanceof Error ? err.message : "Publish failed";
105926
- 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
+ });
105927
106131
  }
105928
106132
  });
105929
106133
  router13.get("/messages", (_req, res) => {
@@ -105998,9 +106202,7 @@ function createRelayRouter(relayCore2, adapterManager2, traceStore2) {
105998
106202
  });
105999
106203
  router13.get("/dead-letters", async (_req, res) => {
106000
106204
  const endpointHash = _req.query.endpointHash;
106001
- const deadLetters = await relayCore2.getDeadLetters(
106002
- endpointHash ? { endpointHash } : void 0
106003
- );
106205
+ const deadLetters = await relayCore2.getDeadLetters(endpointHash ? { endpointHash } : void 0);
106004
106206
  return res.json(deadLetters);
106005
106207
  });
106006
106208
  router13.get("/dead-letters/aggregated", async (_req, res) => {
@@ -106297,9 +106499,7 @@ var TraceStore = class {
106297
106499
  const rows = this.db.select({
106298
106500
  metadata: relayTraces.metadata,
106299
106501
  sentAt: relayTraces.sentAt
106300
- }).from(relayTraces).where(
106301
- sql`json_extract(${relayTraces.metadata}, '$.adapterId') = ${adapterId}`
106302
- ).all();
106502
+ }).from(relayTraces).where(sql`json_extract(${relayTraces.metadata}, '$.adapterId') = ${adapterId}`).all();
106303
106503
  const VALID_CHANNEL_TYPES = /* @__PURE__ */ new Set(["dm", "group", "channel", "thread"]);
106304
106504
  const chatMap = /* @__PURE__ */ new Map();
106305
106505
  for (const row of rows) {
@@ -106694,11 +106894,10 @@ var DenialList = class {
106694
106894
  * onConflictDoUpdate on the unique `path` column.
106695
106895
  *
106696
106896
  * @param filePath - Absolute path to the project directory
106697
- * @param strategy - Strategy name that detected the directory
106698
106897
  * @param reason - Human-readable reason for denial (optional)
106699
106898
  * @param denier - Identifier of the entity performing the denial (e.g., "user", "system")
106700
106899
  */
106701
- deny(filePath, strategy, reason, denier) {
106900
+ deny(filePath, reason, denier) {
106702
106901
  const canonicalPath = this.canonicalize(filePath);
106703
106902
  this.db.insert(agentDenials).values({
106704
106903
  id: generateUlid4(),
@@ -106757,9 +106956,6 @@ var DenialList = class {
106757
106956
  rowToRecord(row) {
106758
106957
  return {
106759
106958
  path: row.path,
106760
- // DenialRecord requires strategy but agentDenials schema doesn't have it;
106761
- // use 'manual' as default since strategy was dropped in the schema migration.
106762
- strategy: "manual",
106763
106959
  reason: row.reason ?? void 0,
106764
106960
  deniedBy: row.denier ?? "unknown",
106765
106961
  deniedAt: row.createdAt
@@ -107156,7 +107352,10 @@ function validateNamespace(ns) {
107156
107352
  return { valid: false, reason: "Namespace must not be empty" };
107157
107353
  }
107158
107354
  if (ns.length > MAX_NAMESPACE_LENGTH) {
107159
- 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
+ };
107160
107359
  }
107161
107360
  return { valid: true };
107162
107361
  }
@@ -107247,7 +107446,6 @@ function manifestDiffersFromEntry(manifest, entry) {
107247
107446
 
107248
107447
  // ../mesh/dist/discovery/unified-scanner.js
107249
107448
  import fs18 from "fs/promises";
107250
- import { realpathSync as realpathSync2 } from "fs";
107251
107449
  import path29 from "path";
107252
107450
 
107253
107451
  // ../mesh/dist/discovery/types.js
@@ -107313,7 +107511,7 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107313
107511
  if (followSymlinks) {
107314
107512
  let realDir;
107315
107513
  try {
107316
- realDir = realpathSync2(dir);
107514
+ realDir = await fs18.realpath(dir);
107317
107515
  } catch {
107318
107516
  continue;
107319
107517
  }
@@ -107330,7 +107528,9 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107330
107528
  }
107331
107529
  let entries;
107332
107530
  try {
107333
- entries = await fs18.readdir(dir, { withFileTypes: true });
107531
+ entries = await fs18.readdir(dir, {
107532
+ withFileTypes: true
107533
+ });
107334
107534
  } catch (err) {
107335
107535
  const code3 = err.code;
107336
107536
  if (code3 === "EACCES" || code3 === "EPERM") {
@@ -107368,7 +107568,7 @@ async function* unifiedScan(options, strategies, registry2, denialList) {
107368
107568
  for (const entry of entries) {
107369
107569
  const isDir = entry.isDirectory();
107370
107570
  const isSymlink = entry.isSymbolicLink();
107371
- if (!isDir && !(followSymlinks && isSymlink))
107571
+ if (!isDir && !isSymlink)
107372
107572
  continue;
107373
107573
  if (isSymlink && !followSymlinks)
107374
107574
  continue;
@@ -107653,9 +107853,8 @@ function listCrossNamespaceRules(deps) {
107653
107853
  }
107654
107854
 
107655
107855
  // ../mesh/dist/mesh-denial.js
107656
- var DEFAULT_REGISTRAR2 = "mesh";
107657
- async function deny(deps, filePath, reason, denier = DEFAULT_REGISTRAR2) {
107658
- deps.denialList.deny(filePath, "manual", reason, denier);
107856
+ async function deny(deps, filePath, reason, denier = DEFAULT_REGISTRAR) {
107857
+ deps.denialList.deny(filePath, reason, denier);
107659
107858
  }
107660
107859
  async function undeny(deps, filePath) {
107661
107860
  deps.denialList.clear(filePath);
@@ -107694,8 +107893,23 @@ var MeshCore = class {
107694
107893
  this.relayBridge = relayBridge;
107695
107894
  this.defaultScanRoot = defaultScanRoot;
107696
107895
  this.logger = logger3;
107697
- this.discoveryDeps = { registry: registry2, denialList, relayBridge, strategies, defaultScanRoot, logger: logger3, generateUlid: monotonicFactory() };
107698
- 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
+ };
107699
107913
  this.denialDeps = { denialList };
107700
107914
  }
107701
107915
  // --- Discovery & Registration ---
@@ -107897,9 +108111,7 @@ function enrichAgent(agent, namespace, deps, scheduleCounts, relayEndpoints) {
107897
108111
  if (relaySubject && relayEndpoints.length > 0) {
107898
108112
  try {
107899
108113
  const nsPrefix = `relay.agent.${namespace}.`;
107900
- const matchingEndpoints = relayEndpoints.filter(
107901
- (ep) => ep.subject.startsWith(nsPrefix)
107902
- );
108114
+ const matchingEndpoints = relayEndpoints.filter((ep) => ep.subject.startsWith(nsPrefix));
107903
108115
  relayAdapters = matchingEndpoints.map((ep) => ep.subject.slice(nsPrefix.length)).filter(Boolean);
107904
108116
  } catch {
107905
108117
  }
@@ -107973,7 +108185,9 @@ function createMeshRouter(deps) {
107973
108185
  const name = overrides?.name;
107974
108186
  const runtime = overrides?.runtime;
107975
108187
  if (!name || !runtime) {
107976
- 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
+ });
107977
108191
  }
107978
108192
  try {
107979
108193
  const manifest = await meshCore2.registerByPath(
@@ -108296,7 +108510,7 @@ var import_ip_address = __toESM(require_ip_address(), 1);
108296
108510
  import { isIPv6 } from "node:net";
108297
108511
  import { isIPv6 as isIPv62 } from "node:net";
108298
108512
  import { Buffer as Buffer2 } from "node:buffer";
108299
- import { createHash as createHash2 } from "node:crypto";
108513
+ import { createHash } from "node:crypto";
108300
108514
  import { isIP } from "node:net";
108301
108515
  function ipKeyGenerator(ip, ipv6Subnet = 56) {
108302
108516
  if (ipv6Subnet && isIPv6(ip)) {
@@ -108460,7 +108674,7 @@ var getResetSeconds = (windowMs, resetTime) => {
108460
108674
  return resetSeconds;
108461
108675
  };
108462
108676
  var getPartitionKey = (key) => {
108463
- const hash = createHash2("sha256");
108677
+ const hash = createHash("sha256");
108464
108678
  hash.update(key);
108465
108679
  const partitionKey = hash.digest("hex").slice(0, 12);
108466
108680
  return Buffer2.from(partitionKey).toString("base64");
@@ -114790,17 +115004,21 @@ function createExternalMcpServer(deps) {
114790
115004
  },
114791
115005
  handleGetServerInfo
114792
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
+ };
114793
115011
  server.tool(
114794
115012
  "get_session_count",
114795
- "Returns the number of sessions visible in the SDK transcript directory.",
114796
- {},
115013
+ "Returns the number of sessions for a specific agent. Provide either agent_id (ULID) or cwd (working directory path).",
115014
+ agentScopeSchema2,
114797
115015
  createGetSessionCountHandler(deps)
114798
115016
  );
114799
115017
  server.tool(
114800
- "get_current_agent",
114801
- "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.",
114802
- {},
114803
- 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)
114804
115022
  );
114805
115023
  server.tool(
114806
115024
  "pulse_list_schedules",
@@ -114900,14 +115118,14 @@ function createExternalMcpServer(deps) {
114900
115118
  createRelayRegisterEndpointHandler(deps)
114901
115119
  );
114902
115120
  server.tool(
114903
- "relay_query",
115121
+ "relay_send_and_wait",
114904
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.',
114905
115123
  {
114906
115124
  to_subject: z27.string().describe('Target subject for the message (e.g., "relay.agent.{agentId}")'),
114907
115125
  payload: z27.unknown().describe("Message payload (any JSON-serializable value)"),
114908
115126
  from: z27.string().describe("Sender subject identifier"),
114909
115127
  timeout_ms: z27.number().int().min(1e3).max(6e5).optional().describe(
114910
- "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."
114911
115129
  ),
114912
115130
  budget: z27.object({
114913
115131
  maxHops: z27.number().int().min(1).optional().describe("Max hop count"),
@@ -114918,8 +115136,8 @@ function createExternalMcpServer(deps) {
114918
115136
  createRelayQueryHandler(deps)
114919
115137
  );
114920
115138
  server.tool(
114921
- "relay_dispatch",
114922
- "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.",
114923
115141
  {
114924
115142
  to_subject: z27.string().describe('Target subject (e.g., "relay.agent.{agentId}")'),
114925
115143
  payload: z27.unknown().describe("Message payload"),
@@ -114934,7 +115152,7 @@ function createExternalMcpServer(deps) {
114934
115152
  );
114935
115153
  server.tool(
114936
115154
  "relay_unregister_endpoint",
114937
- "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).",
114938
115156
  {
114939
115157
  subject: z27.string().describe("Subject of the endpoint to unregister")
114940
115158
  },
@@ -116372,14 +116590,20 @@ function createMcpRouter(serverFactory) {
116372
116590
  router13.get("/", (_req, res) => {
116373
116591
  res.status(405).json({
116374
116592
  jsonrpc: "2.0",
116375
- 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
+ },
116376
116597
  id: null
116377
116598
  });
116378
116599
  });
116379
116600
  router13.delete("/", (_req, res) => {
116380
116601
  res.status(405).json({
116381
116602
  jsonrpc: "2.0",
116382
- 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
+ },
116383
116607
  id: null
116384
116608
  });
116385
116609
  });
@@ -116414,10 +116638,7 @@ function validateMcpOrigin(req, res, next) {
116414
116638
  return;
116415
116639
  }
116416
116640
  const port = env.DORKOS_PORT;
116417
- const allowed = [
116418
- `http://localhost:${port}`,
116419
- `http://127.0.0.1:${port}`
116420
- ];
116641
+ const allowed = [`http://localhost:${port}`, `http://127.0.0.1:${port}`];
116421
116642
  const tunnelUrl = tunnelManager.status.url;
116422
116643
  if (tunnelUrl) {
116423
116644
  allowed.push(new URL(tunnelUrl).origin);
@@ -116488,7 +116709,10 @@ async function start() {
116488
116709
  logger.info("[Runtime] ClaudeCodeRuntime registered as default");
116489
116710
  }
116490
116711
  const schedulerConfig = configManager.get("scheduler");
116491
- 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
+ );
116492
116716
  let pulseStore;
116493
116717
  if (pulseEnabled) {
116494
116718
  try {
@@ -116501,8 +116725,11 @@ async function start() {
116501
116725
  }
116502
116726
  }
116503
116727
  const relayConfig = configManager.get("relay");
116504
- const relayEnabled = "DORKOS_RELAY_ENABLED" in process.env ? env.DORKOS_RELAY_ENABLED : relayConfig?.enabled ?? false;
116505
- 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");
116506
116733
  if (relayEnabled) {
116507
116734
  try {
116508
116735
  adapterRegistry = new AdapterRegistry();
@@ -116584,23 +116811,36 @@ async function start() {
116584
116811
  };
116585
116812
  claudeRuntime.setMcpServerFactory(() => ({ dorkos: createDorkOsToolServer(mcpToolDeps) }));
116586
116813
  const mcpAuthMode = env.MCP_API_KEY ? "auth: API key" : "auth: none";
116587
- app.use("/mcp", validateMcpOrigin, mcpApiKeyAuth, createMcpRouter(() => createExternalMcpServer(mcpToolDeps)));
116814
+ app.use(
116815
+ "/mcp",
116816
+ validateMcpOrigin,
116817
+ mcpApiKeyAuth,
116818
+ createMcpRouter(() => createExternalMcpServer(mcpToolDeps))
116819
+ );
116588
116820
  logger.info(`[MCP] External MCP server mounted at /mcp (stateless, ${mcpAuthMode})`);
116589
116821
  }
116590
116822
  if (pulseEnabled && pulseStore && claudeRuntime) {
116591
- schedulerService = new SchedulerService(pulseStore, claudeRuntime, {
116592
- maxConcurrentRuns: schedulerConfig.maxConcurrentRuns,
116593
- retentionCount: schedulerConfig.retentionCount,
116594
- timezone: schedulerConfig.timezone
116595
- }, relayCore, meshCore);
116596
- app.use("/api/pulse", createPulseRouter(pulseStore, schedulerService, 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
+ );
116834
+ app.use("/api/pulse", createPulseRouter(pulseStore, schedulerService, dorkHome, meshCore));
116597
116835
  setPulseEnabled(true);
116598
116836
  logger.info("[Pulse] Routes mounted and scheduler configured");
116599
116837
  if (meshCore) {
116600
116838
  meshCore.onUnregister((agentId) => {
116601
116839
  const disabledCount = pulseStore.disableSchedulesByAgentId(agentId);
116602
116840
  if (disabledCount > 0) {
116603
- 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
+ );
116604
116844
  }
116605
116845
  });
116606
116846
  }
@@ -116621,11 +116861,14 @@ async function start() {
116621
116861
  app.use("/api/discovery", createDiscoveryRouter(meshCore));
116622
116862
  logger.info("[Discovery] Routes mounted");
116623
116863
  }
116624
- app.use("/api/admin", createAdminRouter({
116625
- dorkHome,
116626
- shutdownServices,
116627
- closeDb: () => db.$client.close()
116628
- }));
116864
+ app.use(
116865
+ "/api/admin",
116866
+ createAdminRouter({
116867
+ dorkHome,
116868
+ shutdownServices,
116869
+ closeDb: () => db.$client.close()
116870
+ })
116871
+ );
116629
116872
  logger.info("[Admin] Routes mounted");
116630
116873
  finalizeApp(app);
116631
116874
  if (relayCore) {
@@ -116640,12 +116883,9 @@ async function start() {
116640
116883
  logger.info("[Pulse] Scheduler started");
116641
116884
  }
116642
116885
  if (claudeRuntime) {
116643
- healthCheckInterval = setInterval(
116644
- () => {
116645
- claudeRuntime.checkSessionHealth();
116646
- },
116647
- INTERVALS.HEALTH_CHECK_MS
116648
- );
116886
+ healthCheckInterval = setInterval(() => {
116887
+ claudeRuntime.checkSessionHealth();
116888
+ }, INTERVALS.HEALTH_CHECK_MS);
116649
116889
  }
116650
116890
  if (env.TUNNEL_ENABLED) {
116651
116891
  const tunnelPort = env.TUNNEL_PORT ?? PORT;
@@ -116665,7 +116905,10 @@ async function start() {
116665
116905
  ...isDevPort && { mode: `dev (Vite on :${tunnelPort})` }
116666
116906
  });
116667
116907
  } catch (err) {
116668
- 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
+ );
116669
116912
  }
116670
116913
  }
116671
116914
  }