@gururea/opencode-commandcode-provider 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/README.md CHANGED
@@ -34,7 +34,7 @@ Restart opencode, then:
34
34
  - **`commandcode_status` tool / `/commandcode-status`.** Shows plugin diagnostics: catalog source (live/cache/fallback), model count, last fetch time, endpoint, zero-data-retention setting, and version.
35
35
  - Command Code API keys (`user_...`) do not expire, so they are stored once and reused.
36
36
 
37
- > The `/commandcode-quota` and `/commandcode-status` **tools** are registered by the plugin. The corresponding **slash commands** are provided as `.opencode/command/*.md` files in the package, which you can copy into your project's `.opencode/command/` directory if your opencode setup does not auto-discover package commands.
37
+ > The plugin installs the `commandcode-quota.md` and `commandcode-status.md` slash-command files into your project's `.opencode/command/` directory on startup, so the `/commandcode-quota` and `/commandcode-status` commands appear in the TUI autocomplete. The commands invoke the corresponding tools registered by the plugin.
38
38
 
39
39
  ## Environment variables
40
40
 
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import { homedir } from "os";
3
- import { join } from "path";
3
+ import { join as join2 } from "path";
4
4
 
5
5
  // src/auth.ts
6
6
  import { randomBytes } from "crypto";
@@ -237,6 +237,41 @@ function createAuthHook(options = {}) {
237
237
  };
238
238
  }
239
239
 
240
+ // src/commands.ts
241
+ import { mkdir, readFile, writeFile } from "fs/promises";
242
+ import { join } from "path";
243
+ var QUOTA_TEMPLATE = `---
244
+ description: Show Command Code account usage and quota (credits, plan, usage)
245
+ ---
246
+
247
+ Use the **commandcode_quota** tool to fetch and report the user's Command Code account usage and quota. Summarize the credits remaining and used, the plan, the billing-period usage (cost, requests, tokens), and the 5-hour and weekly usage windows. If no API key is configured, tell the user to run \`/connect\` and select Command Code.
248
+ `;
249
+ var STATUS_TEMPLATE = `---
250
+ description: Show Command Code plugin diagnostics (catalog source, model count, endpoint)
251
+ ---
252
+
253
+ Use the **commandcode_status** tool to fetch and report the Command Code plugin diagnostics: the model catalog source (live/cache/fallback), model count, when the catalog was last fetched, the API endpoint, the zero-data-retention setting, and the plugin version.
254
+ `;
255
+ var COMMANDS = [
256
+ { name: "commandcode-quota.md", content: QUOTA_TEMPLATE },
257
+ { name: "commandcode-status.md", content: STATUS_TEMPLATE }
258
+ ];
259
+ async function installCommandFiles(directory) {
260
+ if (!directory) return;
261
+ const commandDir = join(directory, ".opencode", "command");
262
+ await mkdir(commandDir, { recursive: true });
263
+ for (const command of COMMANDS) {
264
+ const target = join(commandDir, command.name);
265
+ try {
266
+ const existing = await readFile(target, "utf-8");
267
+ if (existing === command.content) continue;
268
+ return;
269
+ } catch {
270
+ }
271
+ await writeFile(target, command.content, "utf-8");
272
+ }
273
+ }
274
+
240
275
  // src/quota-tool.ts
241
276
  import { tool } from "@opencode-ai/plugin";
242
277
 
@@ -743,7 +778,7 @@ function createStatusTool({
743
778
  }
744
779
 
745
780
  // src/models.ts
746
- import { mkdir, readFile, rename, rm, writeFile } from "fs/promises";
781
+ import { mkdir as mkdir2, readFile as readFile2, rename, rm, writeFile as writeFile2 } from "fs/promises";
747
782
  import { dirname } from "path";
748
783
  var DEFAULT_PROVIDER_API_BASE = "https://api.commandcode.ai/provider/v1";
749
784
  var DEFAULT_MODELS_URL = `${DEFAULT_PROVIDER_API_BASE}/models`;
@@ -970,14 +1005,14 @@ function commandCodeModelsFromCache(value) {
970
1005
  return models;
971
1006
  }
972
1007
  async function readCommandCodeModelsCache(cachePath) {
973
- const contents = await readFile(cachePath, "utf-8");
1008
+ const contents = await readFile2(cachePath, "utf-8");
974
1009
  return commandCodeModelsFromCache(JSON.parse(contents));
975
1010
  }
976
1011
  async function writeCommandCodeModelsCache(cachePath, models, fetchedAt = Date.now()) {
977
- await mkdir(dirname(cachePath), { recursive: true });
1012
+ await mkdir2(dirname(cachePath), { recursive: true });
978
1013
  const temporaryPath = `${cachePath}.${process.pid}.tmp`;
979
1014
  try {
980
- await writeFile(
1015
+ await writeFile2(
981
1016
  temporaryPath,
982
1017
  `${JSON.stringify({ version: MODEL_CACHE_VERSION, fetchedAt, models }, null, 2)}
983
1018
  `,
@@ -1033,7 +1068,7 @@ async function loadCommandCodeModels(options) {
1033
1068
  }
1034
1069
  async function cachedTimestamp(cachePath) {
1035
1070
  try {
1036
- const contents = await readFile(cachePath, "utf-8");
1071
+ const contents = await readFile2(cachePath, "utf-8");
1037
1072
  const parsed = JSON.parse(contents);
1038
1073
  if (!isRecord3(parsed)) return null;
1039
1074
  return typeof parsed.fetchedAt === "number" && Number.isFinite(parsed.fetchedAt) ? parsed.fetchedAt : null;
@@ -1123,7 +1158,7 @@ function providerBaseUrl() {
1123
1158
  function modelsCachePath() {
1124
1159
  const configured = process.env.COMMANDCODE_MODELS_CACHE;
1125
1160
  if (configured && configured.length > 0) return configured;
1126
- return join(homedir(), ".cache", "opencode", "commandcode-models.json");
1161
+ return join2(homedir(), ".cache", "opencode", "commandcode-models.json");
1127
1162
  }
1128
1163
  async function loadProviderModels(modelsUrl, cachePath, providerBaseUrl2, logWarn, logInfo) {
1129
1164
  const result = await loadCommandCodeModels({
@@ -1149,10 +1184,12 @@ function getModelsTimeoutMs() {
1149
1184
  const parsed = Number(raw);
1150
1185
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MODELS_TIMEOUT_MS;
1151
1186
  }
1152
- var CommandCodePlugin = async ({ client }) => {
1187
+ var CommandCodePlugin = async ({ client, directory }) => {
1153
1188
  const apiBase = providerBaseUrl();
1154
1189
  const modelsUrl = process.env.COMMANDCODE_MODELS_URL ?? `${apiBase}/models`;
1155
1190
  const cachePath = modelsCachePath();
1191
+ installCommandFiles(directory).catch(() => {
1192
+ });
1156
1193
  const { modelMap: models, modelsInfo } = await loadProviderModels(
1157
1194
  modelsUrl,
1158
1195
  cachePath,
@@ -1179,6 +1216,15 @@ var CommandCodePlugin = async ({ client }) => {
1179
1216
  },
1180
1217
  models
1181
1218
  };
1219
+ cfg.command ??= {};
1220
+ cfg.command["commandcode-quota"] = {
1221
+ description: "Show Command Code account usage and quota (credits, plan, usage)",
1222
+ template: "Use the commandcode_quota tool to fetch and report the user's Command Code account usage and quota. Summarize credits remaining and used, the plan, billing-period usage (cost, requests, tokens), and the 5-hour and weekly usage windows."
1223
+ };
1224
+ cfg.command["commandcode-status"] = {
1225
+ description: "Show Command Code plugin diagnostics (catalog source, model count, endpoint)",
1226
+ template: "Use the commandcode_status tool to fetch and report the Command Code plugin diagnostics: catalog source (live/cache/fallback), model count, last fetch time, API endpoint, zero-data-retention setting, and plugin version."
1227
+ };
1182
1228
  client.app.log({
1183
1229
  body: {
1184
1230
  service: "opencode-commandcode",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gururea/opencode-commandcode-provider",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "OpenCode plugin that adds the Command Code (commandcode.ai) provider and its authentication to the interface.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",