@sjawhar/opencode-legion-envoy 0.6.1 → 0.7.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/dist/bin/dispatch-mcp-shim.js +0 -6
- package/dist/src/server.js +23 -38
- package/package.json +1 -1
- package/src/server.ts +1 -1
- package/src/dispatch-subscribe.ts +0 -52
|
@@ -13834,12 +13834,6 @@ function isJsonRpcRequest(value) {
|
|
|
13834
13834
|
return value.id === null || typeof value.id === "string" || typeof value.id === "number";
|
|
13835
13835
|
}
|
|
13836
13836
|
function dispatchShimGate(env, options = {}) {
|
|
13837
|
-
if (env.LEGION_TREE !== undefined || env.LEGION_CONTROLLER === "1") {
|
|
13838
|
-
return {
|
|
13839
|
-
serve: false,
|
|
13840
|
-
reason: "Legion sessions use envoy_dispatch via the daemon; not serving the raw dispatch tool"
|
|
13841
|
-
};
|
|
13842
|
-
}
|
|
13843
13837
|
const remoteUrl = resolveDispatchMcpUrl(env, options);
|
|
13844
13838
|
if (remoteUrl === null) {
|
|
13845
13839
|
return {
|
package/dist/src/server.js
CHANGED
|
@@ -13754,21 +13754,6 @@ var LegionDaemonApi = {
|
|
|
13754
13754
|
request: architectCapability.extend({ issue: nonEmptyString, comment: exports_external.string().optional() }),
|
|
13755
13755
|
response: exports_external.object({})
|
|
13756
13756
|
},
|
|
13757
|
-
DispatchThread: {
|
|
13758
|
-
request: exports_external.strictObject({
|
|
13759
|
-
tree: nonEmptyString,
|
|
13760
|
-
issue: nonEmptyString,
|
|
13761
|
-
role: legionRole,
|
|
13762
|
-
sessionId: nonEmptyString,
|
|
13763
|
-
secret: nonEmptyString,
|
|
13764
|
-
parent: nonEmptyString,
|
|
13765
|
-
subject: nonEmptyString,
|
|
13766
|
-
body: nonEmptyString,
|
|
13767
|
-
ask: exports_external.unknown().optional(),
|
|
13768
|
-
urgency: exports_external.enum(["low", "med", "high", "blocking"]).optional()
|
|
13769
|
-
}),
|
|
13770
|
-
response: exports_external.object({ thread: exports_external.number().int(), url: nonEmptyString })
|
|
13771
|
-
},
|
|
13772
13757
|
SpawnToken: {
|
|
13773
13758
|
request: architectCapability.extend({ issue: nonEmptyString, role: legionRole }),
|
|
13774
13759
|
response: exports_external.object({ spawnToken: nonEmptyString })
|
|
@@ -13858,6 +13843,29 @@ function normalizeEnvoyUrl(value) {
|
|
|
13858
13843
|
return value.replace(/\/+$/, "");
|
|
13859
13844
|
}
|
|
13860
13845
|
|
|
13846
|
+
// ../envoy-client/src/dispatch-subscribe.ts
|
|
13847
|
+
var ISSUE_URL_RE = /https?:\/\/github\.com\/([^/\s"]+)\/([^/\s"]+)\/issues\/(\d+)/i;
|
|
13848
|
+
var DISPATCH_TOOL_RE = /(^|[-._])dispatch$/i;
|
|
13849
|
+
function isDispatchTool(tool) {
|
|
13850
|
+
return DISPATCH_TOOL_RE.test(tool);
|
|
13851
|
+
}
|
|
13852
|
+
function dispatchThreadTopic(owner, repo, thread) {
|
|
13853
|
+
return `notifications.github.${owner}.${repo}.issue.${thread}.>`;
|
|
13854
|
+
}
|
|
13855
|
+
function dispatchSubscriptionTopic(tool, output) {
|
|
13856
|
+
if (!isDispatchTool(tool))
|
|
13857
|
+
return null;
|
|
13858
|
+
const match = ISSUE_URL_RE.exec(output);
|
|
13859
|
+
if (!match)
|
|
13860
|
+
return null;
|
|
13861
|
+
const owner = match[1];
|
|
13862
|
+
const repo = match[2];
|
|
13863
|
+
const thread = Number(match[3]);
|
|
13864
|
+
if (!Number.isInteger(thread) || thread <= 0)
|
|
13865
|
+
return null;
|
|
13866
|
+
return dispatchThreadTopic(owner, repo, thread);
|
|
13867
|
+
}
|
|
13868
|
+
|
|
13861
13869
|
// ../envoy-client/src/machine.ts
|
|
13862
13870
|
import { hostname as hostname3 } from "os";
|
|
13863
13871
|
function machineID() {
|
|
@@ -14182,29 +14190,6 @@ function injectEnvoyMcp(cfg, entry) {
|
|
|
14182
14190
|
return {};
|
|
14183
14191
|
}
|
|
14184
14192
|
|
|
14185
|
-
// src/dispatch-subscribe.ts
|
|
14186
|
-
var ISSUE_URL_RE = /https?:\/\/github\.com\/([^/\s"]+)\/([^/\s"]+)\/issues\/(\d+)/i;
|
|
14187
|
-
var DISPATCH_TOOL_RE = /(^|[-._])dispatch$/i;
|
|
14188
|
-
function isDispatchTool(tool2) {
|
|
14189
|
-
return DISPATCH_TOOL_RE.test(tool2);
|
|
14190
|
-
}
|
|
14191
|
-
function dispatchThreadTopic(owner, repo, thread) {
|
|
14192
|
-
return `notifications.github.${owner}.${repo}.issue.${thread}.>`;
|
|
14193
|
-
}
|
|
14194
|
-
function dispatchSubscriptionTopic(tool2, output) {
|
|
14195
|
-
if (!isDispatchTool(tool2))
|
|
14196
|
-
return null;
|
|
14197
|
-
const match = ISSUE_URL_RE.exec(output);
|
|
14198
|
-
if (!match)
|
|
14199
|
-
return null;
|
|
14200
|
-
const owner = match[1];
|
|
14201
|
-
const repo = match[2];
|
|
14202
|
-
const thread = Number(match[3]);
|
|
14203
|
-
if (!Number.isInteger(thread) || thread <= 0)
|
|
14204
|
-
return null;
|
|
14205
|
-
return dispatchThreadTopic(owner, repo, thread);
|
|
14206
|
-
}
|
|
14207
|
-
|
|
14208
14193
|
// src/port.ts
|
|
14209
14194
|
import { execFile } from "child_process";
|
|
14210
14195
|
|
package/package.json
CHANGED
package/src/server.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { agentSubject } from "@legion/contracts";
|
|
2
2
|
import { envoyDefaultsFromEnvironment } from "@legion/envoy-client/defaults";
|
|
3
|
+
import { dispatchSubscriptionTopic } from "@legion/envoy-client/dispatch-subscribe";
|
|
3
4
|
import { machineID } from "@legion/envoy-client/machine";
|
|
4
5
|
import { envoyToolSpecs } from "@legion/envoy-client/tool-contract";
|
|
5
6
|
import { createEnvoyClient } from "@legion/envoy-client/transport";
|
|
6
7
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7
8
|
import { loadEnvoyConfig } from "./config";
|
|
8
9
|
import { buildDispatchMcpEntry, injectEnvoyMcp } from "./dispatch-mcp";
|
|
9
|
-
import { dispatchSubscriptionTopic } from "./dispatch-subscribe";
|
|
10
10
|
import { logger } from "./log";
|
|
11
11
|
import { resolvePort } from "./port";
|
|
12
12
|
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Auto-subscription wiring for the envoy_dispatch MCP tool.
|
|
2
|
-
//
|
|
3
|
-
// When an agent opens a Dispatch thread via the envoy_dispatch MCP tool, the
|
|
4
|
-
// human answers by commenting on the resulting GitHub sub-issue. For the agent
|
|
5
|
-
// to RECEIVE that answer, its session must be subscribed to the thread's Envoy
|
|
6
|
-
// topic (notifications.github.<owner>.<repo>.issue.<thread>.>). The dispatch
|
|
7
|
-
// tool is served by the Go dispatch server and has no OpenCode session context,
|
|
8
|
-
// so we close the loop in the plugin (which does know the session id) from the
|
|
9
|
-
// tool.execute.after hook.
|
|
10
|
-
//
|
|
11
|
-
// This module is the pure, testable core: it turns a completed tool execution
|
|
12
|
-
// into the topic the calling session should subscribe to, or null when the
|
|
13
|
-
// execution isn't a successful envoy_dispatch call.
|
|
14
|
-
|
|
15
|
-
// Matches a GitHub issue URL anywhere in the tool output and captures
|
|
16
|
-
// owner / repo / number. The dispatch tool returns {"thread":N,"url":"…"} as
|
|
17
|
-
// its text content, so the URL is always present on success.
|
|
18
|
-
const ISSUE_URL_RE = /https?:\/\/github\.com\/([^/\s"]+)\/([^/\s"]+)\/issues\/(\d+)/i;
|
|
19
|
-
|
|
20
|
-
// The tool is registered on the Go MCP server as "dispatch" and exposed to
|
|
21
|
-
// OpenCode under the "envoy" MCP server (so commonly "envoy_dispatch"). Accept
|
|
22
|
-
// any separator a client might use while still excluding unrelated tools.
|
|
23
|
-
const DISPATCH_TOOL_RE = /(^|[-._])dispatch$/i;
|
|
24
|
-
|
|
25
|
-
export function isDispatchTool(tool: string): boolean {
|
|
26
|
-
return DISPATCH_TOOL_RE.test(tool);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Build the Envoy topic carrying every event on a dispatch thread issue. */
|
|
30
|
-
export function dispatchThreadTopic(owner: string, repo: string, thread: number): string {
|
|
31
|
-
return `notifications.github.${owner}.${repo}.issue.${thread}.>`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Given a completed tool execution (name + textual output), return the Envoy
|
|
36
|
-
* topic the calling session should subscribe to so it receives replies on the
|
|
37
|
-
* dispatch thread — or null when this isn't a successful envoy_dispatch call.
|
|
38
|
-
*
|
|
39
|
-
* Parsing the GitHub issue URL out of the output (rather than trusting a JSON
|
|
40
|
-
* field) keeps this robust to however OpenCode surfaces the MCP result: owner,
|
|
41
|
-
* repo, and thread number all come from the canonical issue URL.
|
|
42
|
-
*/
|
|
43
|
-
export function dispatchSubscriptionTopic(tool: string, output: string): string | null {
|
|
44
|
-
if (!isDispatchTool(tool)) return null;
|
|
45
|
-
const match = ISSUE_URL_RE.exec(output);
|
|
46
|
-
if (!match) return null;
|
|
47
|
-
const owner = match[1] as string;
|
|
48
|
-
const repo = match[2] as string;
|
|
49
|
-
const thread = Number(match[3]);
|
|
50
|
-
if (!Number.isInteger(thread) || thread <= 0) return null;
|
|
51
|
-
return dispatchThreadTopic(owner, repo, thread);
|
|
52
|
-
}
|