opencode-anthropic-fix 2.1.1 → 2.2.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/tui.mjs ADDED
@@ -0,0 +1,93 @@
1
+ import { anthropicCommandRpc, sanitizeCommandOutput, validateCommandArguments } from "./lib/host/command-rpc.mjs";
2
+
3
+ /**
4
+ * V1 keeps its existing server slash-command hook. V2 consumes setup(), while
5
+ * modern v1 consumes tui(); neither path loads a different host's SDK.
6
+ */
7
+ export default {
8
+ id: "opencode-anthropic-fix",
9
+ async tui() {
10
+ // The v1 server already owns /anthropic and its noReply presentation.
11
+ },
12
+ setup(context) {
13
+ const rpc = context.client.rpc(anthropicCommandRpc);
14
+ const pending = new Set();
15
+ let disposed = false;
16
+ let creatingSession;
17
+
18
+ async function sessionForCommand(signal) {
19
+ const route = context.ui.router.current();
20
+ if (route.type === "session") return route.sessionID;
21
+ // The home screen has no session yet. Creating an empty session provides
22
+ // stable state for two-step OAuth without creating a model prompt.
23
+ creatingSession ??= context.client.session.create({ location: context.location }, { signal }).finally(() => {
24
+ creatingSession = undefined;
25
+ });
26
+ const session = await creatingSession;
27
+ signal.throwIfAborted();
28
+ if (!session?.id) throw new Error("OpenCode could not create a session for the Anthropic command.");
29
+ context.ui.router.navigate({ type: "session", sessionID: session.id });
30
+ return session.id;
31
+ }
32
+
33
+ const commandLayer = () => ({
34
+ enabled: () => !disposed,
35
+ commands: [
36
+ {
37
+ id: "anthropic.manage",
38
+ title: "Manage Anthropic accounts",
39
+ description: "Authentication, account selection, usage and configuration",
40
+ group: "Anthropic",
41
+ palette: true,
42
+ slash: { name: "anthropic", arguments: true },
43
+ async run(input = "") {
44
+ if (disposed) return;
45
+ const controller = new AbortController();
46
+ pending.add(controller);
47
+ try {
48
+ const args = validateCommandArguments(input);
49
+ const sessionID = await sessionForCommand(controller.signal);
50
+ const result = await rpc.execute(
51
+ { sessionID, arguments: args },
52
+ { signal: controller.signal, location: context.location },
53
+ );
54
+ if (disposed || controller.signal.aborted) return;
55
+ if (typeof result?.output !== "string") throw new Error("Invalid Anthropic command response.");
56
+ await context.ui.dialog.alert({
57
+ title: "Anthropic",
58
+ message: sanitizeCommandOutput(result.output, args) || "Command completed.",
59
+ });
60
+ } catch (error) {
61
+ if (disposed || controller.signal.aborted) return;
62
+ context.ui.toast.show({
63
+ title: "Anthropic",
64
+ variant: "error",
65
+ message: sanitizeCommandOutput(error?.message || "Anthropic command failed.", input),
66
+ });
67
+ } finally {
68
+ pending.delete(controller);
69
+ }
70
+ },
71
+ },
72
+ ],
73
+ });
74
+
75
+ // OpenCode 2.0.21/2.0.22 calls setup outside the Solid provider owner.
76
+ // Register from the app slot so Keymap.Provider is available and the
77
+ // layer's reactive lifetime follows the mounted plugin contribution.
78
+ const removeSlot = context.ui.slot({
79
+ append: "app",
80
+ render() {
81
+ if (disposed) return null;
82
+ context.keymap.layer(commandLayer);
83
+ return null;
84
+ },
85
+ });
86
+
87
+ return () => {
88
+ disposed = true;
89
+ removeSlot();
90
+ for (const controller of pending) controller.abort();
91
+ };
92
+ },
93
+ };