@joe-broadhead/opencode-slack 0.0.3 → 0.0.4
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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/assets/icon.svg +1 -0
- package/dist/index.js +32 -12
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
4
|
|
|
5
|
+
## [0.0.4] - 2026-11-04
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Jelly shows the plugin's one-line summary and icon: `jelly.summary`, and `jelly.icon`, a speech bubble on a muted slate tile, shipped as `assets/icon.svg`.
|
|
10
|
+
- In Jelly, a web tab can sign in to Slack through Jelly's sign-in relay: the `slack` sign-in declares `relay`, and `docs/jelly.md` gives the relay address to add to your Slack app. The app manifest still lists only the loopback address.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The tools RPC, without a Slack app client ID, refuses with `CLIENT_ID_MISSING` (or `CLIENT_ID_INVALID` for a client ID saved in `/connect` that is empty or has spaces) instead of `NOT_REGISTERED`, with `/slack-status`'s next step: run `/connect`, choose Slack app and paste the client ID. `describe` gives the same code as each method's `reason`. `NOT_REGISTERED` now means a client ID is set but OpenCode has not registered the server, and its next step is to run `/slack-status`.
|
|
15
|
+
- The README's sign-out step says what to do when `opencode mcp logout slack` answers "MCP server not found" right after OpenCode starts: wait a few seconds and run it again.
|
|
16
|
+
|
|
5
17
|
## [0.0.3] - 2026-11-04
|
|
6
18
|
|
|
7
19
|
### Added
|
package/README.md
CHANGED
|
@@ -207,7 +207,7 @@ A script's errors from the tools RPC have their own codes, listed in [Scripting]
|
|
|
207
207
|
|
|
208
208
|
Sign out while the plugin is still installed: once it is removed, OpenCode no longer knows the `slack` server or the **Slack app** entry, so it cannot remove their credentials, and `opencode auth list` stops showing them.
|
|
209
209
|
|
|
210
|
-
1. Sign out of Slack: `opencode mcp logout slack`.
|
|
210
|
+
1. Sign out of Slack: `opencode mcp logout slack`. If it answers "MCP server not found" right after OpenCode starts, wait a few seconds and run it again.
|
|
211
211
|
2. If you saved a client ID in `/connect`, remove it: `opencode auth logout slack-app`, and choose the **Slack app** account. Without a terminal, name it: `opencode auth logout slack-app "Slack app"`.
|
|
212
212
|
3. Check: `opencode auth list` lists neither **Slack** nor **Slack app**.
|
|
213
213
|
4. Remove the plugin: `opencode plugin remove @joe-broadhead/opencode-slack`, then `opencode reload`. `opencode mcp list` no longer lists `slack`.
|
package/assets/icon.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48"><rect width="48" height="48" rx="12" fill="#475569"/><g fill="none" stroke="#FFFFFF" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 12h18a5 5 0 0 1 5 5v10a5 5 0 0 1-5 5H23l-7 6v-6h-1a5 5 0 0 1-5-5V17a5 5 0 0 1 5-5z"/><path d="M17 20h14"/><path d="M17 25.5h9"/></g></svg>
|
package/dist/index.js
CHANGED
|
@@ -155,8 +155,8 @@ var NEXT_STEPS = {
|
|
|
155
155
|
CONNECTING: "Wait a few seconds, then call the method again.",
|
|
156
156
|
CONNECTION_FAILED: "Run /slack-status and follow its next step.",
|
|
157
157
|
DISABLED: "Enable the Slack server in /mcps, then call the method again.",
|
|
158
|
-
//
|
|
159
|
-
NOT_REGISTERED: "Run /
|
|
158
|
+
// Without a client ID, setup's notRegistered hook gives CLIENT_ID_MISSING or CLIENT_ID_INVALID and /connect instead.
|
|
159
|
+
NOT_REGISTERED: "Run /slack-status and follow its next step.",
|
|
160
160
|
TOOL_UNAVAILABLE: "Call describe to see which methods OpenCode lists now, and run /slack-status.",
|
|
161
161
|
UPSTREAM_ERROR: "Check the input against the method's schema from describe, and run /slack-status if it keeps failing.",
|
|
162
162
|
CANCELLED: "Call the method again if you still need the result."
|
|
@@ -188,6 +188,7 @@ var DESCRIBED = object(
|
|
|
188
188
|
description: STRING,
|
|
189
189
|
available: { type: "boolean" },
|
|
190
190
|
reason: STRING,
|
|
191
|
+
detail: STRING,
|
|
191
192
|
input: ANY_OBJECT,
|
|
192
193
|
output: ANY_OBJECT
|
|
193
194
|
},
|
|
@@ -321,12 +322,15 @@ async function registerToolsRpc(ctx, options) {
|
|
|
321
322
|
const rules = [...agent.data.permissions, ...info.permissions ?? []];
|
|
322
323
|
return { agent: info.agent, rules };
|
|
323
324
|
};
|
|
325
|
+
const notRegistered = (server) => mcp?.notRegistered?.(server);
|
|
324
326
|
const unavailable = async (server, tool, connected) => {
|
|
325
327
|
const status2 = (await ctx.mcp.list()).data.find((entry) => entry.name === server)?.status.status;
|
|
326
328
|
const code = connection(status2) ?? connected;
|
|
327
329
|
if (code === "TOOL_UNAVAILABLE") return fail(code, `OpenCode does not list ${tool} on the connected "${server}" server`);
|
|
328
330
|
if (status2 === "connected") return fail(code, `the "${server}" server was reconnecting when ${tool} ran`);
|
|
329
|
-
|
|
331
|
+
const what = `the "${server}" server ${STATUS_TEXT[code] ?? "is unavailable"}`;
|
|
332
|
+
const own = code === "NOT_REGISTERED" ? notRegistered(server) : void 0;
|
|
333
|
+
return own ? new ScriptError({ code: own.code, what, next: own.next }) : fail(code, what);
|
|
330
334
|
};
|
|
331
335
|
const denied = (action, error, asked = action) => {
|
|
332
336
|
const reason = upstreamText(record(error) && typeof error["message"] === "string" ? error["message"] : String(error));
|
|
@@ -358,11 +362,15 @@ async function registerToolsRpc(ctx, options) {
|
|
|
358
362
|
}
|
|
359
363
|
};
|
|
360
364
|
};
|
|
361
|
-
const ownedTarget = (spec, envelope2) =>
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
365
|
+
const ownedTarget = (spec, envelope2) => {
|
|
366
|
+
if (accounts) serverOf(envelope2.account);
|
|
367
|
+
const account = accounts && envelope2.account !== void 0 ? { account: envelope2.account } : {};
|
|
368
|
+
return {
|
|
369
|
+
action: spec.action,
|
|
370
|
+
mcp: false,
|
|
371
|
+
run: async (call) => await spec.run(envelope2.input, { ...call, ...account }) ?? null
|
|
372
|
+
};
|
|
373
|
+
};
|
|
366
374
|
const invoke = async (target, raw, context) => {
|
|
367
375
|
const envelope2 = raw;
|
|
368
376
|
let method;
|
|
@@ -415,7 +423,9 @@ async function registerToolsRpc(ctx, options) {
|
|
|
415
423
|
for (const name of KNOWN_READS) {
|
|
416
424
|
const id = `${server}_${name}`;
|
|
417
425
|
const tool = managed ? tools.find((entry) => entry.id === id) : void 0;
|
|
418
|
-
const
|
|
426
|
+
const code = !managed ? "SERVER_CONFLICT" : tool ? void 0 : connection(status2) ?? "TOOL_UNAVAILABLE";
|
|
427
|
+
const reason = code === "NOT_REGISTERED" ? notRegistered(server)?.code ?? code : code;
|
|
428
|
+
const detail = code === void 0 ? void 0 : mcp.unavailableDetail?.(name, code);
|
|
419
429
|
const input = jsonSchema(tool?.input) ?? ANY_OBJECT;
|
|
420
430
|
const output = jsonSchema(tool?.output);
|
|
421
431
|
methods.push({
|
|
@@ -426,6 +436,7 @@ async function registerToolsRpc(ctx, options) {
|
|
|
426
436
|
description: tool?.description ?? "",
|
|
427
437
|
available: reason === void 0,
|
|
428
438
|
...reason ? { reason } : {},
|
|
439
|
+
...detail === void 0 ? {} : { detail },
|
|
429
440
|
input,
|
|
430
441
|
output: mcpOutput(output)
|
|
431
442
|
});
|
|
@@ -830,12 +841,15 @@ function buildStatus(input) {
|
|
|
830
841
|
...base,
|
|
831
842
|
state: "not_configured",
|
|
832
843
|
...input.client.invalid ? { code: "CLIENT_ID_INVALID", message: `The client ID saved in the /connect ${app} entry is empty or has spaces, so Slack is not added.` } : { code: "CLIENT_ID_MISSING", message: `No Slack app client ID is set, so Slack is not added. To create the app, use the manifest at ${APP_MANIFEST_URL}.` },
|
|
833
|
-
nextStep:
|
|
844
|
+
nextStep: clientNextStep(server)
|
|
834
845
|
};
|
|
835
846
|
}
|
|
836
847
|
const status2 = input.servers.find((item) => item.name === server)?.status;
|
|
837
848
|
return { ...base, ...connection2(server, status2, unguardedAgents, names.length) };
|
|
838
849
|
}
|
|
850
|
+
function clientNextStep(server) {
|
|
851
|
+
return `Run /connect and choose ${appDisplayName(server)}, then paste your Slack app's client ID.`;
|
|
852
|
+
}
|
|
839
853
|
function callbackRow(callback, port) {
|
|
840
854
|
const register = "register exactly this URL in the app's Redirect URLs";
|
|
841
855
|
if (port === void 0) return `${callback} (${register})`;
|
|
@@ -899,7 +913,7 @@ function formatStatus(status2) {
|
|
|
899
913
|
}
|
|
900
914
|
|
|
901
915
|
// src/version.ts
|
|
902
|
-
var VERSION = "0.0.
|
|
916
|
+
var VERSION = "0.0.4";
|
|
903
917
|
|
|
904
918
|
// src/index.ts
|
|
905
919
|
var STARTUP_POLL_MS = 250;
|
|
@@ -1007,7 +1021,13 @@ var src_default = Plugin.define({
|
|
|
1007
1021
|
}
|
|
1008
1022
|
});
|
|
1009
1023
|
const stopTools = options === void 0 ? async () => {
|
|
1010
|
-
} : await registerToolsRpc(ctx, {
|
|
1024
|
+
} : await registerToolsRpc(ctx, {
|
|
1025
|
+
mcp: {
|
|
1026
|
+
server: options.server,
|
|
1027
|
+
managed: () => !nameInUse,
|
|
1028
|
+
notRegistered: () => client.client !== void 0 ? void 0 : { code: client.invalid ? "CLIENT_ID_INVALID" : "CLIENT_ID_MISSING", next: clientNextStep(options.server) }
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1011
1031
|
await ctx.command.transform((editor) => {
|
|
1012
1032
|
editor.add({
|
|
1013
1033
|
name: "slack-status",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joe-broadhead/opencode-slack",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Unofficial OpenCode plugin for Slack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opencode",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
+
"assets/icon.svg",
|
|
26
27
|
"skills",
|
|
27
28
|
"README.md",
|
|
28
29
|
"LICENSE",
|
|
@@ -58,6 +59,8 @@
|
|
|
58
59
|
},
|
|
59
60
|
"jelly": {
|
|
60
61
|
"title": "Slack",
|
|
62
|
+
"summary": "Search and read Slack; anything that sends asks first.",
|
|
63
|
+
"icon": "assets/icon.svg",
|
|
61
64
|
"tools": [
|
|
62
65
|
{
|
|
63
66
|
"name": "slack.slack_search_public",
|
|
@@ -242,7 +245,8 @@
|
|
|
242
245
|
"id": "slack",
|
|
243
246
|
"label": "Slack",
|
|
244
247
|
"server": "slack",
|
|
245
|
-
"after": "app"
|
|
248
|
+
"after": "app",
|
|
249
|
+
"relay": {}
|
|
246
250
|
}
|
|
247
251
|
],
|
|
248
252
|
"contributes": {
|