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