@jeffreyjyz/opencode-command-code 0.2.0 → 0.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/dist/index.js CHANGED
@@ -612,24 +612,6 @@ var commandCodeV2 = Plugin.define({
612
612
  editor.models.set(lane.id, seed[lane.id]);
613
613
  }
614
614
  });
615
- await ctx.command.transform((editor) => {
616
- editor.add({
617
- name: "cmd-usage",
618
- description: "Show Command Code plan, credits, and usage windows",
619
- execute: async ({ sessionID, prompt }) => {
620
- const arg = typeof prompt?.text === "string" ? prompt.text : "";
621
- let text;
622
- try {
623
- text = await runCmduse(arg, { env: key ? { CMD_API_KEY: key } : undefined });
624
- } catch (e) {
625
- text = `cmd-usage failed: ${e instanceof Error ? e.message : String(e)}`;
626
- }
627
- await ctx.session.synthetic({ sessionID, text: `**/cmd-usage**
628
-
629
- ${text}` });
630
- }
631
- });
632
- });
633
615
  await ctx.tool.transform((editor) => {
634
616
  editor.add({
635
617
  name: "cmd_usage",
package/dist/tui.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Plugin } from "@opencode/plugin/tui";
2
+ declare const _default: Plugin.Definition;
3
+ export default _default;
package/dist/tui.js ADDED
@@ -0,0 +1,165 @@
1
+ // @bun
2
+ // src/tui.ts
3
+ import { Plugin } from "@opencode/plugin/tui";
4
+
5
+ // src/cli.ts
6
+ import { spawn } from "child_process";
7
+ var CANDIDATES = ["cmduse", "/opt/homebrew/bin/cmduse", "/usr/local/bin/cmduse"];
8
+ var DEFAULT_ARGS = ["-1", "--plain"];
9
+ var SUBCOMMANDS = new Set([
10
+ "plans",
11
+ "models",
12
+ "daily",
13
+ "hourly",
14
+ "model",
15
+ "session",
16
+ "statusline",
17
+ "config"
18
+ ]);
19
+ function splitCliArgs(input) {
20
+ const out = [];
21
+ let cur = "";
22
+ let has = false;
23
+ let quote;
24
+ for (let i = 0;i < input.length; i++) {
25
+ const ch = input[i] ?? "";
26
+ if (quote) {
27
+ if (ch === quote) {
28
+ quote = undefined;
29
+ } else if (ch === "\\" && quote === '"' && i + 1 < input.length) {
30
+ cur += input[++i];
31
+ } else {
32
+ cur += ch;
33
+ }
34
+ continue;
35
+ }
36
+ if (ch === '"' || ch === "'") {
37
+ quote = ch;
38
+ has = true;
39
+ } else if (ch === "\\") {
40
+ if (i + 1 < input.length)
41
+ cur += input[++i];
42
+ has = true;
43
+ } else if (/\s/.test(ch)) {
44
+ if (has)
45
+ out.push(cur);
46
+ cur = "";
47
+ has = false;
48
+ } else {
49
+ cur += ch;
50
+ has = true;
51
+ }
52
+ }
53
+ if (has)
54
+ out.push(cur);
55
+ return out;
56
+ }
57
+ function buildCmduseArgs(arg) {
58
+ const tokens = splitCliArgs(arg);
59
+ if (!tokens.length)
60
+ return DEFAULT_ARGS;
61
+ if (tokens.some((t) => SUBCOMMANDS.has(t)))
62
+ return tokens;
63
+ return [...DEFAULT_ARGS, ...tokens];
64
+ }
65
+ function stderrTail(text) {
66
+ const lines = text.trimEnd().split(`
67
+ `);
68
+ return lines.slice(-3).join(`
69
+ `).slice(-400);
70
+ }
71
+ function runOnce(bin, args, opts) {
72
+ return new Promise((resolve, reject) => {
73
+ const child = spawn(bin, args, {
74
+ env: { ...process.env, ...opts.env ?? {} },
75
+ stdio: ["ignore", "pipe", "pipe"]
76
+ });
77
+ const out = [];
78
+ const err = [];
79
+ const onAbort = () => child.kill("SIGTERM");
80
+ opts.signal?.addEventListener("abort", onAbort, { once: true });
81
+ child.stdout.on("data", (d) => out.push(d));
82
+ child.stderr.on("data", (d) => err.push(d));
83
+ child.on("error", (e) => {
84
+ opts.signal?.removeEventListener("abort", onAbort);
85
+ reject(e);
86
+ });
87
+ child.on("close", (code, signal) => {
88
+ opts.signal?.removeEventListener("abort", onAbort);
89
+ const stdout = Buffer.concat(out).toString("utf8");
90
+ if (opts.signal?.aborted) {
91
+ reject(new Error("cmduse invocation aborted"));
92
+ } else if (code === 0) {
93
+ resolve(stdout);
94
+ } else {
95
+ const why = signal ? `killed by ${signal}` : `exit ${code}`;
96
+ const tail = stderrTail(Buffer.concat(err).toString("utf8"));
97
+ reject(new Error(`cmduse ${args.join(" ")}: ${why}${tail ? `
98
+ ${tail}` : ""}`));
99
+ }
100
+ });
101
+ });
102
+ }
103
+ async function runCmduse(arg, opts = {}) {
104
+ const args = buildCmduseArgs(arg);
105
+ const candidates = opts.candidates ?? CANDIDATES;
106
+ let last;
107
+ for (const bin of candidates) {
108
+ try {
109
+ return await runOnce(bin, args, opts);
110
+ } catch (e) {
111
+ last = e;
112
+ if (e?.code !== "ENOENT")
113
+ throw e;
114
+ }
115
+ }
116
+ throw new Error(`cmduse binary not found (install: brew install JeffreyJYZ/tap/cmduse)${last instanceof Error && last.message !== last.name ? ` \u2014 ${last.message}` : ""}`, { cause: last });
117
+ }
118
+
119
+ // src/tui.ts
120
+ var tui_default = Plugin.define({
121
+ id: "command-code.tui",
122
+ setup(context) {
123
+ context.ui.slot({
124
+ append: "app",
125
+ render: () => {
126
+ context.keymap.layer(() => ({
127
+ mode: "global",
128
+ priority: 10,
129
+ commands: [
130
+ {
131
+ id: "command-code.cmd-usage",
132
+ title: "Command Code usage",
133
+ group: "Command Code",
134
+ slash: { name: "cmd-usage", arguments: true },
135
+ enabled: () => true,
136
+ suggested: true,
137
+ run: async (input) => {
138
+ let text;
139
+ try {
140
+ text = await runCmduse(input ?? "");
141
+ } catch (e) {
142
+ context.ui.toast.show({
143
+ title: "cmd-usage failed",
144
+ message: e instanceof Error ? e.message : String(e),
145
+ variant: "error"
146
+ });
147
+ return;
148
+ }
149
+ await context.ui.dialog.alert({
150
+ title: "Command Code usage",
151
+ message: text.trimEnd()
152
+ });
153
+ }
154
+ }
155
+ ],
156
+ bindings: ["command-code.cmd-usage"]
157
+ }));
158
+ return null;
159
+ }
160
+ });
161
+ }
162
+ });
163
+ export {
164
+ tui_default as default
165
+ };
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./tui": "./dist/tui.js"
11
+ },
8
12
  "scripts": {
9
- "build": "rm -rf dist && bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode/plugin && tsc -p tsconfig.build.json",
13
+ "build": "rm -rf dist && bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode/plugin --external @opencode/plugin/tui && bun build src/tui.ts --outdir dist --target bun --external @opencode-ai/plugin --external @opencode/plugin --external @opencode/plugin/tui && tsc -p tsconfig.build.json",
10
14
  "test": "bun test",
11
15
  "typecheck": "tsc --noEmit"
12
16
  },
@@ -16,9 +20,10 @@
16
20
  },
17
21
  "devDependencies": {
18
22
  "@types/bun": "latest",
23
+ "solid-js": "^1.9.0",
19
24
  "typescript": "^5"
20
25
  },
21
- "files": ["dist", "LICENSE"],
26
+ "files": ["dist", "tui.js", "LICENSE"],
22
27
  "keywords": ["opencode", "command-code", "plugin", "provider", "ai-sdk"],
23
28
  "license": "MIT",
24
29
  "publishConfig": {
package/tui.js ADDED
@@ -0,0 +1,5 @@
1
+ // Entry shim for local/directory plugin loading: opencode resolves the TUI
2
+ // half as a literal `tui.js` beside the package root (package `exports`
3
+ // are only consulted for npm-installed plugins). Keep this file in sync with
4
+ // the built ./tui output.
5
+ export { default } from "./dist/tui.js"