@sjawhar/opencode-legion-envoy 0.21.0 → 0.22.1
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 +4 -0
- package/dist/src/server.js +43 -13
- package/package.json +1 -1
- package/skills/dispatch/SKILL.md +11 -4
package/README.md
CHANGED
|
@@ -29,6 +29,10 @@ envoy.json (`~/.config/opencode/envoy.json`, merged with `<repo>/.opencode/envoy
|
|
|
29
29
|
the session working directory, stamps it with the OpenCode session id and title, and stores
|
|
30
30
|
`details.topic` as tool metadata so a successful mutation subscribes to that exact Dispatch topic.
|
|
31
31
|
|
|
32
|
+
`dispatch_artifact` accepts exactly one upload source: a local `path`, or inline `content`.
|
|
33
|
+
An architect can post a primary specification directly with
|
|
34
|
+
`{ issue, name: "spec.md", content: "# Design", primary: true }`.
|
|
35
|
+
|
|
32
36
|
It also maintains the live session registry metadata needed for Envoy to discover OpenCode sessions and their API ports.
|
|
33
37
|
|
|
34
38
|
Slack topic examples must use the real Slack `team_id`, for example:
|
package/dist/src/server.js
CHANGED
|
@@ -13590,6 +13590,10 @@ var ChildStatusEventPayloadSchema = object({
|
|
|
13590
13590
|
to: string2().optional()
|
|
13591
13591
|
});
|
|
13592
13592
|
// ../contracts/src/dispatch-tools.ts
|
|
13593
|
+
function dispatchToolSchema(spec, z, opts) {
|
|
13594
|
+
const shape = spec.arguments(z);
|
|
13595
|
+
return spec.validation === undefined ? z.object(shape, opts) : z.refineObject(shape, spec.validation.check, spec.validation.message, opts);
|
|
13596
|
+
}
|
|
13593
13597
|
var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference; an external reference creates its native issue on first use in the repository's mapped project (DISPATCH_REPO_PROJECTS) or, failing that, the default project (DISPATCH_DEFAULT_PROJECT).";
|
|
13594
13598
|
var ASK_URGENCIES = ["low", "med", "high", "blocking"];
|
|
13595
13599
|
var DOC_EDIT_OPS = ["replace", "delete", "insert"];
|
|
@@ -13686,14 +13690,22 @@ var dispatchToolSpecs = [
|
|
|
13686
13690
|
},
|
|
13687
13691
|
{
|
|
13688
13692
|
name: "dispatch_artifact",
|
|
13689
|
-
description: "
|
|
13693
|
+
description: "Attach a local file or inline text as an issue artifact. Do not use it to edit a live document; use " + `dispatch_doc_edit instead. Exactly one of path or content is required; artifacts are limited to 25 MiB. ${ISSUE_REFERENCE}`,
|
|
13690
13694
|
arguments: (z) => ({
|
|
13691
13695
|
issue: z.string().describe(ISSUE_REFERENCE),
|
|
13692
13696
|
name: z.string().describe("Artifact filename shown in Dispatch."),
|
|
13693
|
-
path: z.string().describe("Local path to the file to upload."),
|
|
13697
|
+
path: z.string().describe("Local path to the file to upload.").optional(),
|
|
13698
|
+
content: z.string().describe("Inline text to store as a Markdown document.").optional(),
|
|
13694
13699
|
primary: z.boolean().describe("Make this document the issue primary artifact.").optional(),
|
|
13695
13700
|
summary: z.string().describe("Optional version summary.").optional()
|
|
13696
|
-
})
|
|
13701
|
+
}),
|
|
13702
|
+
validation: {
|
|
13703
|
+
check: (value) => {
|
|
13704
|
+
const input = value;
|
|
13705
|
+
return typeof input.path === "string" !== (typeof input.content === "string");
|
|
13706
|
+
},
|
|
13707
|
+
message: "Exactly one of path or content is required."
|
|
13708
|
+
}
|
|
13697
13709
|
},
|
|
13698
13710
|
{
|
|
13699
13711
|
name: "dispatch_read",
|
|
@@ -14081,7 +14093,18 @@ function zodSchemaApi(zod) {
|
|
|
14081
14093
|
schema = schema.max(opts.max);
|
|
14082
14094
|
return schema;
|
|
14083
14095
|
},
|
|
14084
|
-
object: (shape) =>
|
|
14096
|
+
object: (shape, opts = {}) => {
|
|
14097
|
+
let schema = api.object(shape);
|
|
14098
|
+
if (opts.strict)
|
|
14099
|
+
schema = schema.strict();
|
|
14100
|
+
return schema;
|
|
14101
|
+
},
|
|
14102
|
+
refineObject: (shape, check, message, opts = {}) => {
|
|
14103
|
+
let schema = api.object(shape);
|
|
14104
|
+
if (opts.strict)
|
|
14105
|
+
schema = schema.strict();
|
|
14106
|
+
return schema.refine(check, message);
|
|
14107
|
+
}
|
|
14085
14108
|
};
|
|
14086
14109
|
}
|
|
14087
14110
|
// ../envoy-client/src/defaults.ts
|
|
@@ -14117,9 +14140,6 @@ var DEFAULT_SERVER_URL = "http://localhost:8766";
|
|
|
14117
14140
|
function normalizeDispatchUrl(url2) {
|
|
14118
14141
|
return url2.replace(/\/+$/, "");
|
|
14119
14142
|
}
|
|
14120
|
-
function deprecatedMcpUrl(url2) {
|
|
14121
|
-
return normalizeDispatchUrl(url2).replace(/\/mcp$/, "");
|
|
14122
|
-
}
|
|
14123
14143
|
function parsedDispatchUrl(value, source) {
|
|
14124
14144
|
const url2 = normalizeDispatchUrl(value);
|
|
14125
14145
|
try {
|
|
@@ -14169,7 +14189,6 @@ function readEnvoyFile(filePath) {
|
|
|
14169
14189
|
}
|
|
14170
14190
|
function resolveDispatchConfig(env, options = {}) {
|
|
14171
14191
|
const explicitUrl = env.DISPATCH_URL;
|
|
14172
|
-
const deprecatedUrl = explicitUrl ? undefined : env.DISPATCH_MCP_URL;
|
|
14173
14192
|
const home = options.home ?? env.HOME ?? homedir();
|
|
14174
14193
|
const cwd = options.cwd ?? process.cwd();
|
|
14175
14194
|
const userFile = readEnvoyFile(path.join(home, ".config", "opencode", "envoy.json"));
|
|
@@ -14183,7 +14202,7 @@ function resolveDispatchConfig(env, options = {}) {
|
|
|
14183
14202
|
...userFile.kind === "valid" ? userFile.settings : null,
|
|
14184
14203
|
...repoFile.kind === "valid" ? repoFile.settings : null
|
|
14185
14204
|
};
|
|
14186
|
-
const rawUrl = explicitUrl !== undefined ? { value: explicitUrl, source: "DISPATCH_URL" } :
|
|
14205
|
+
const rawUrl = explicitUrl !== undefined ? { value: explicitUrl, source: "DISPATCH_URL" } : merged.enabled === true ? { value: merged.serverUrl ?? DEFAULT_SERVER_URL, source: "dispatch.serverUrl" } : null;
|
|
14187
14206
|
const url2 = rawUrl ? parsedDispatchUrl(rawUrl.value, rawUrl.source) : { url: null, error: null };
|
|
14188
14207
|
const token = env.DISPATCH_TOKEN ?? merged.token ?? null;
|
|
14189
14208
|
const tokenSource = env.DISPATCH_TOKEN === undefined ? "dispatch.token" : "DISPATCH_TOKEN";
|
|
@@ -14350,6 +14369,9 @@ class DispatchClient {
|
|
|
14350
14369
|
return this.#json("POST", ["api", "v1", "issues", await this.#resolveIssue(issue), "messages"], input);
|
|
14351
14370
|
}
|
|
14352
14371
|
async artifact(issue, input) {
|
|
14372
|
+
const artifactPath = ["api", "v1", "issues", await this.#resolveIssue(issue), "artifacts"];
|
|
14373
|
+
if ("content" in input)
|
|
14374
|
+
return this.#json("POST", artifactPath, input);
|
|
14353
14375
|
const form = new FormData;
|
|
14354
14376
|
form.set("name", input.name);
|
|
14355
14377
|
if (input.primary !== undefined)
|
|
@@ -14359,7 +14381,7 @@ class DispatchClient {
|
|
|
14359
14381
|
if (input.actor !== undefined)
|
|
14360
14382
|
form.set("actor", JSON.stringify(input.actor));
|
|
14361
14383
|
form.set("file", input.file, input.name);
|
|
14362
|
-
return this.#form("POST",
|
|
14384
|
+
return this.#form("POST", artifactPath, form);
|
|
14363
14385
|
}
|
|
14364
14386
|
async getArtifact(id) {
|
|
14365
14387
|
return this.#json("GET", ["api", "v1", "artifacts", id]);
|
|
@@ -14544,7 +14566,7 @@ function toolSchema(tool) {
|
|
|
14544
14566
|
const spec = dispatchToolSpecs.find((candidate) => candidate.name === tool);
|
|
14545
14567
|
if (!spec)
|
|
14546
14568
|
throw new Error(`Unknown Dispatch tool: ${tool}`);
|
|
14547
|
-
return
|
|
14569
|
+
return dispatchToolSchema(spec, zodSchemaApi(exports_external), { strict: true });
|
|
14548
14570
|
}
|
|
14549
14571
|
async function resolveIssueArguments(tool, args, cwd, env, exec) {
|
|
14550
14572
|
if (tool === "dispatch_issue")
|
|
@@ -14826,12 +14848,20 @@ Open anchored asks/comments: ${marks.join(", ")}`,
|
|
|
14826
14848
|
case "dispatch_artifact": {
|
|
14827
14849
|
const primary = optionalBoolean(args, "primary");
|
|
14828
14850
|
const summary = optionalString(args, "summary");
|
|
14829
|
-
const
|
|
14830
|
-
|
|
14851
|
+
const name = stringArg(args, "name");
|
|
14852
|
+
const content = optionalString(args, "content");
|
|
14853
|
+
const result = await client.artifact(issue(), content === undefined ? {
|
|
14854
|
+
name,
|
|
14831
14855
|
file: Bun.file(resolvePath(input.cwd, stringArg(args, "path"))),
|
|
14832
14856
|
...primary === undefined ? {} : { primary },
|
|
14833
14857
|
...summary === undefined ? {} : { summary },
|
|
14834
14858
|
actor
|
|
14859
|
+
} : {
|
|
14860
|
+
name,
|
|
14861
|
+
content,
|
|
14862
|
+
...primary === undefined ? {} : { primary },
|
|
14863
|
+
...summary === undefined ? {} : { summary },
|
|
14864
|
+
actor
|
|
14835
14865
|
});
|
|
14836
14866
|
return {
|
|
14837
14867
|
text: `Uploaded ${result.artifact.name} as version ${result.version.number}`,
|
package/package.json
CHANGED
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -105,15 +105,22 @@ invalid actor, route, or primary artifact.
|
|
|
105
105
|
|
|
106
106
|
## Artifacts
|
|
107
107
|
|
|
108
|
-
Attach an image, diagram, or file with:
|
|
108
|
+
Attach an image, diagram, or local file with:
|
|
109
109
|
|
|
110
110
|
```ts
|
|
111
111
|
dispatch_artifact({ issue, name, path, primary?, summary? })
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
Or, when the text is already in the call, post a Markdown document directly:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
dispatch_artifact({ issue, name: "spec.md", content: "# Design\n...", primary: true })
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Exactly one of `path` and `content` is required. The inline form sends JSON with
|
|
121
|
+
`Content-Type: application/json`. It returns `details` `{ issue, topic, artifact, version }`.
|
|
122
|
+
Uploading the same `name` creates its next version. Use `content` for an architect's primary spec;
|
|
123
|
+
set `primary: true` only for Markdown documents.
|
|
117
124
|
|
|
118
125
|
## Messages
|
|
119
126
|
|