@jeffreyjyz/opencode-command-code 0.3.0 → 0.3.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
@@ -3751,6 +3751,19 @@ function staticSeedModels() {
3751
3751
  }
3752
3752
  return seed;
3753
3753
  }
3754
+ function mergeModels(snapshot, live) {
3755
+ const byId = new Map;
3756
+ const add = (model) => {
3757
+ const id = model?.id;
3758
+ if (typeof id === "string")
3759
+ byId.set(id, model);
3760
+ };
3761
+ for (const model of snapshot)
3762
+ add(model);
3763
+ for (const model of live)
3764
+ add(model);
3765
+ return [...byId.values()];
3766
+ }
3754
3767
  async function credentialKey(ctx) {
3755
3768
  try {
3756
3769
  const connection = await ctx.integration.connection.active(INTEGRATION_ID);
@@ -3771,17 +3784,14 @@ async function credentialKey(ctx) {
3771
3784
  var commandCodeV2 = {
3772
3785
  id: PLUGIN_ID,
3773
3786
  async setup(ctx) {
3787
+ const t0 = Date.now();
3774
3788
  let localKey;
3789
+ let keyMs = 0;
3775
3790
  try {
3791
+ const keyStart = Date.now();
3776
3792
  localKey = await resolveKey();
3793
+ keyMs = Date.now() - keyStart;
3777
3794
  } catch {}
3778
- let hasConnection = false;
3779
- try {
3780
- hasConnection = await ctx.integration.connection.active(INTEGRATION_ID) !== undefined;
3781
- } catch {}
3782
- if (!localKey && !hasConnection) {
3783
- console.warn(`[command-code] no API key found. Run /connect and choose "${INTEGRATION_NAME}", or \`cmd login\` (~/.commandcode/auth.json), or set CMD_API_KEY.`);
3784
- }
3785
3795
  await ctx.integration.transform((editor) => {
3786
3796
  editor.update(INTEGRATION_ID, (integration) => {
3787
3797
  if (integration.name === integration.id) {
@@ -3816,9 +3826,9 @@ var commandCodeV2 = {
3816
3826
  provider.name = lane.name;
3817
3827
  if (provider.package === "")
3818
3828
  provider.package = lane.pkg;
3819
- provider.activation = hasConnection || localKey ? "enabled" : "auto";
3829
+ provider.activation = localKey ? "enabled" : "auto";
3820
3830
  provider.settings = { ...provider.settings, baseURL: PROVIDER_BASE };
3821
- if (!hasConnection && localKey && provider.settings.apiKey === undefined) {
3831
+ if (localKey && provider.settings.apiKey === undefined) {
3822
3832
  provider.settings.apiKey = localKey;
3823
3833
  }
3824
3834
  provider.integrationID ??= INTEGRATION_ID;
@@ -3826,6 +3836,7 @@ var commandCodeV2 = {
3826
3836
  editor.models.set(lane.id, seed[lane.id]);
3827
3837
  }
3828
3838
  });
3839
+ const registerMs = Date.now() - t0;
3829
3840
  await ctx.tool.transform((editor) => {
3830
3841
  editor.add({
3831
3842
  name: "cmd_usage",
@@ -3849,12 +3860,32 @@ var commandCodeV2 = {
3849
3860
  }
3850
3861
  });
3851
3862
  });
3863
+ let hasConnection = false;
3864
+ let connectionMs = 0;
3865
+ try {
3866
+ const connectionStart = Date.now();
3867
+ hasConnection = await ctx.integration.connection.active(INTEGRATION_ID) !== undefined;
3868
+ connectionMs = Date.now() - connectionStart;
3869
+ } catch {}
3870
+ if (hasConnection) {
3871
+ await ctx.provider.transform((editor) => {
3872
+ for (const lane of LANES) {
3873
+ editor.update(lane.id, (provider) => {
3874
+ provider.activation = "enabled";
3875
+ });
3876
+ }
3877
+ });
3878
+ }
3879
+ if (!localKey && !hasConnection) {
3880
+ console.warn(`[command-code] no API key found. Run /connect and choose "${INTEGRATION_NAME}", or \`cmd login\` (~/.commandcode/auth.json), or set CMD_API_KEY.`);
3881
+ }
3852
3882
  const controller = new AbortController;
3853
3883
  let refreshing = false;
3854
3884
  const refresh = async () => {
3855
3885
  if (refreshing || controller.signal.aborted)
3856
3886
  return;
3857
3887
  refreshing = true;
3888
+ const refreshStart = Date.now();
3858
3889
  try {
3859
3890
  const key = await credentialKey(ctx);
3860
3891
  if (!key)
@@ -3863,11 +3894,12 @@ var commandCodeV2 = {
3863
3894
  if (controller.signal.aborted)
3864
3895
  return;
3865
3896
  await ctx.provider.transform((editor) => {
3866
- editor.models.set("command-code-anthropic", split.claude.map((m) => toV2Model(m, LANES[0])));
3867
- editor.models.set("command-code-openai", split.open.map((m) => toV2Model(m, LANES[1])));
3897
+ editor.models.set("command-code-anthropic", mergeModels(seed["command-code-anthropic"], split.claude.map((m) => toV2Model(m, LANES[0]))));
3898
+ editor.models.set("command-code-openai", mergeModels(seed["command-code-openai"], split.open.map((m) => toV2Model(m, LANES[1]))));
3868
3899
  });
3900
+ console.log(`[command-code] setup: key=${keyMs}ms register=${registerMs}ms connection=${connectionMs}ms refresh=${Date.now() - refreshStart}ms models=${split.claude.length + split.open.length}`);
3869
3901
  } catch (e) {
3870
- console.warn("[command-code] live model list unavailable, keeping previous list:", e);
3902
+ console.warn("[command-code] live model list unavailable, keeping the snapshot:", e);
3871
3903
  } finally {
3872
3904
  refreshing = false;
3873
3905
  }
@@ -3883,7 +3915,7 @@ var commandCodeV2 = {
3883
3915
  // package.json
3884
3916
  var package_default = {
3885
3917
  name: "@jeffreyjyz/opencode-command-code",
3886
- version: "0.3.0",
3918
+ version: "0.3.1",
3887
3919
  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.",
3888
3920
  type: "module",
3889
3921
  main: "dist/index.js",
@@ -8,3 +8,9 @@ export declare const WEEKLY_SECS: number;
8
8
  * the same unit cmduse-core's vectors pin.
9
9
  */
10
10
  export declare function elapsedPct(resetAtMs: number | undefined, durSecs: number, nowSecs: number): number | undefined;
11
+ /**
12
+ * `elapsedPct` as text: a seven-day window forty minutes in is 0.4%, and "0%"
13
+ * reads as "not started". Non-zero fractions below a percent render "<1%".
14
+ * Exact zero stays "0%".
15
+ */
16
+ export declare function elapsedLabel(resetAtMs: number | undefined, durSecs: number, nowSecs: number): string | undefined;
package/dist/tui.js CHANGED
@@ -403,6 +403,14 @@ function elapsedPct(resetAtMs, durSecs, nowSecs) {
403
403
  const pct = (nowSecs - start) / durSecs * 100;
404
404
  return Math.round(Math.min(100, Math.max(0, pct)));
405
405
  }
406
+ function elapsedLabel(resetAtMs, durSecs, nowSecs) {
407
+ const pct = elapsedPct(resetAtMs, durSecs, nowSecs);
408
+ if (pct === undefined)
409
+ return;
410
+ if (pct === 0 && nowSecs > Math.floor(resetAtMs / 1000) - durSecs)
411
+ return "<1%";
412
+ return `${pct}%`;
413
+ }
406
414
 
407
415
  // src/sidebar/rows.ts
408
416
  var TIER_DISPLAY = {
@@ -445,9 +453,9 @@ function windowRow(label, w, now, durSecs) {
445
453
  return;
446
454
  const used = typeof w.used === "number" ? w.used : 0;
447
455
  const pct = Math.round(used / w.cap * 100);
448
- const elapsed = elapsedPct(w.resetAt, durSecs, Math.floor(now / 1000));
456
+ const elapsed = elapsedLabel(w.resetAt, durSecs, Math.floor(now / 1000));
449
457
  const reset = until(w.resetAt, now);
450
- const parts = [`${money(used)} / ${money(w.cap)} (${pct}%)`, ...elapsed === undefined ? [] : [`${elapsed}% elapsed`], ...reset ? [`resets ${reset}`] : []];
458
+ const parts = [`${money(used)} / ${money(w.cap)} (${pct}%)`, ...elapsed === undefined ? [] : [`${elapsed} elapsed`], ...reset ? [`resets ${reset}`] : []];
451
459
  return [label, parts.join(" \xB7 ")];
452
460
  }
453
461
  function usageRows(usage, now = Date.now()) {
package/dist/v2.d.ts CHANGED
@@ -21,9 +21,15 @@ export declare const TOOL_DESCRIPTION = "Fetch live Command Code plan/usage: pla
21
21
  * only the open lane needs the reasoning round-trip field. */
22
22
  export declare function toV2Model(m: CmdModel, lane: Lane): unknown;
23
23
  /** Instant static seed from gating.json's known model ids, split by wire lane.
24
- * Replaced by the gated live list once the background fetch lands; also the
25
- * fallback shown when the live fetch fails. */
24
+ * Shows in /model immediately; the live fetch merges over it later. */
26
25
  export declare function staticSeedModels(): Record<Lane["id"], unknown[]>;
26
+ /**
27
+ * Union by model id: the snapshot keeps every id it had, so a gated or partial
28
+ * live response can never make a model vanish from the picker, while live
29
+ * entries win field-by-field so context, rates, variants and modalities stay
30
+ * fresh. Snapshot order is preserved; live-only models append in live order.
31
+ */
32
+ export declare function mergeModels(snapshot: readonly unknown[], live: readonly unknown[]): unknown[];
27
33
  /** The slice of the plugin context the credential resolver needs. */
28
34
  type CredentialContext = {
29
35
  integration: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.3.0",
3
+ "version": "0.3.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",