@jeffreyjyz/opencode-command-code 0.3.8 → 0.3.10

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
@@ -4063,7 +4063,7 @@ var commandCodeV2 = {
4063
4063
  // package.json
4064
4064
  var package_default = {
4065
4065
  name: "@jeffreyjyz/opencode-command-code",
4066
- version: "0.3.8",
4066
+ version: "0.3.10",
4067
4067
  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.",
4068
4068
  type: "module",
4069
4069
  main: "dist/index.js",
@@ -37,6 +37,12 @@ export declare function legacyColors(theme: {
37
37
  text: RGBA;
38
38
  textMuted: RGBA;
39
39
  }): PanelColors;
40
+ /**
41
+ * Colours off: every tone renders as plain text, so only bold and dim carry
42
+ * structure. Headlines lose their accent, status rows their green/amber/red —
43
+ * which is the point of the default.
44
+ */
45
+ export declare function mono(colors: PanelColors): PanelColors;
40
46
  /** Bold title, then one line per row. Renders nothing when there are no rows. */
41
47
  export declare function Panel(props: {
42
48
  rows: () => SidebarRow[];
@@ -0,0 +1,10 @@
1
+ export interface Prefs {
2
+ colors: boolean;
3
+ }
4
+ export declare const DEFAULTS: Prefs;
5
+ /** Preferences live beside opencode's own config, XDG layout honoured. */
6
+ export declare function prefsPath(env?: NodeJS.ProcessEnv): string;
7
+ /** Only a literal `true` enables colour, so a typo cannot turn the panel on. */
8
+ export declare function parsePrefs(raw: unknown): Prefs;
9
+ /** Env override, then the file, then the default. Cached for `CACHE_MS`. */
10
+ export declare function loadPrefs(env?: NodeJS.ProcessEnv, now?: number): Prefs;
@@ -1 +1,14 @@
1
- export declare function useRows(activeModelId: () => string | undefined, active: () => boolean): import("solid-js").Accessor<import("./rows").SidebarRow[]>;
1
+ import { type SidebarRow, type Usage } from "./rows";
2
+ /** Which provider a session is on, as far as this panel is concerned. */
3
+ export type SessionKind = "ours" | "other" | "unknown";
4
+ /**
5
+ * `unknown` is the frame during a session switch, before the host has resolved
6
+ * the new session's model. It must not be read as "another provider", or the
7
+ * panel blanks and refetches on every tab change.
8
+ */
9
+ export declare function sessionKind(providerID: string | undefined): SessionKind;
10
+ /** Keep an account snapshot for the next panel that needs it. */
11
+ export declare function rememberSnapshot(snapshot: Usage): void;
12
+ /** Rows to paint before this panel's first fetch of the session completes. */
13
+ export declare function seededRows(): SidebarRow[];
14
+ export declare function useRows(activeModelId: () => string | undefined, providerID: () => string | undefined): import("solid-js").Accessor<SidebarRow[]>;
package/dist/tui.js CHANGED
@@ -643,6 +643,18 @@ function legacyColors(theme) {
643
643
  crit: RGBA.fromValues(0.88, 0.42, 0.46, 1)
644
644
  };
645
645
  }
646
+ function mono(colors) {
647
+ return {
648
+ base: colors.base,
649
+ muted: colors.muted,
650
+ strong: colors.base,
651
+ label: colors.base,
652
+ headline: colors.base,
653
+ ok: colors.base,
654
+ warn: colors.base,
655
+ crit: colors.base
656
+ };
657
+ }
646
658
  var spanStyle = (fg) => ({
647
659
  style: {
648
660
  fg
@@ -710,6 +722,50 @@ function Panel(props) {
710
722
  });
711
723
  }
712
724
 
725
+ // src/sidebar/prefs.ts
726
+ import { readFileSync } from "fs";
727
+ import { homedir } from "os";
728
+ import { join } from "path";
729
+ var DEFAULTS = {
730
+ colors: false
731
+ };
732
+ var CACHE_MS = 5000;
733
+ var cached;
734
+ function prefsPath(env = process.env) {
735
+ const base = env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
736
+ return join(base, "opencode", "command-code.json");
737
+ }
738
+ function parsePrefs(raw) {
739
+ const value = raw?.colors;
740
+ return {
741
+ colors: value === true
742
+ };
743
+ }
744
+ function loadPrefs(env = process.env, now = Date.now()) {
745
+ if (cached && now - cached.at < CACHE_MS)
746
+ return cached.prefs;
747
+ const flag = env.CMD_COLORS;
748
+ let prefs = DEFAULTS;
749
+ if (flag === "1" || flag === "true")
750
+ prefs = {
751
+ colors: true
752
+ };
753
+ else if (flag === "0" || flag === "false")
754
+ prefs = {
755
+ colors: false
756
+ };
757
+ else {
758
+ try {
759
+ prefs = parsePrefs(JSON.parse(readFileSync(prefsPath(env), "utf8")));
760
+ } catch {}
761
+ }
762
+ cached = {
763
+ at: now,
764
+ prefs
765
+ };
766
+ return prefs;
767
+ }
768
+
713
769
  // src/sidebar/useRows.ts
714
770
  import { createEffect, createMemo, createSignal, onCleanup } from "solid-js";
715
771
 
@@ -1776,10 +1832,10 @@ function minPlan(id) {
1776
1832
  // src/sidebar/data.ts
1777
1833
  import { spawn as spawn2 } from "child_process";
1778
1834
  import { mkdir, readFile, writeFile } from "fs/promises";
1779
- import { homedir } from "os";
1780
- import { dirname, join } from "path";
1835
+ import { homedir as homedir2 } from "os";
1836
+ import { dirname, join as join2 } from "path";
1781
1837
  var CMDUSE = cmduseCandidates();
1782
- var MPC = ["mpc", join(homedir(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
1838
+ var MPC = ["mpc", join2(homedir2(), ".bun/bin/mpc"), "/opt/homebrew/bin/mpc"];
1783
1839
  var CACHE_TTL_MS = 6 * 60 * 60 * 1000;
1784
1840
  var SPAWN_OPTIONS = {
1785
1841
  stdio: ["ignore", "pipe", "pipe"],
@@ -1856,8 +1912,8 @@ function parseMpcJson(text) {
1856
1912
  return meta;
1857
1913
  }
1858
1914
  function cachePath() {
1859
- const base = process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache");
1860
- return join(base, "command-code", "cc-catalog.json");
1915
+ const base = process.env.XDG_CACHE_HOME ?? join2(homedir2(), ".cache");
1916
+ return join2(base, "command-code", "cc-catalog.json");
1861
1917
  }
1862
1918
  async function loadMeta() {
1863
1919
  try {
@@ -1885,13 +1941,13 @@ async function loadUsage() {
1885
1941
 
1886
1942
  // src/sidebar/usageDb.ts
1887
1943
  import { Database } from "bun:sqlite";
1888
- import { homedir as homedir2 } from "os";
1889
- import { join as join2 } from "path";
1944
+ import { homedir as homedir3 } from "os";
1945
+ import { join as join3 } from "path";
1890
1946
  function usageDbPath() {
1891
1947
  if (process.env.OPENCODE_DB)
1892
1948
  return process.env.OPENCODE_DB;
1893
- const base = process.env.XDG_DATA_HOME ?? join2(homedir2(), ".local", "share");
1894
- return join2(base, "opencode", "opencode.db");
1949
+ const base = process.env.XDG_DATA_HOME ?? join3(homedir3(), ".local", "share");
1950
+ return join3(base, "opencode", "opencode.db");
1895
1951
  }
1896
1952
  function periodStart(usage, now = Date.now()) {
1897
1953
  if (typeof usage.periodStartAt === "number")
@@ -1953,28 +2009,47 @@ function loadModelUsage(modelID, sinceMs, path = usageDbPath()) {
1953
2009
 
1954
2010
  // src/sidebar/useRows.ts
1955
2011
  var POLL_MS = 60000;
1956
- function useRows(activeModelId, active) {
1957
- const [usage, setUsage] = createSignal([]);
2012
+ function sessionKind(providerID) {
2013
+ if (!providerID)
2014
+ return "unknown";
2015
+ return providerID.startsWith("command-code") ? "ours" : "other";
2016
+ }
2017
+ var lastSnapshot;
2018
+ function rememberSnapshot(snapshot) {
2019
+ lastSnapshot = snapshot;
2020
+ }
2021
+ function seededRows() {
2022
+ return lastSnapshot ? usageRows(lastSnapshot) : [];
2023
+ }
2024
+ function useRows(activeModelId, providerID) {
2025
+ const [usage, setUsage] = createSignal(seededRows());
1958
2026
  const [meta, setMeta] = createSignal(new Map);
1959
2027
  const [modelUsage, setModelUsage] = createSignal();
2028
+ const [wasOurs, setWasOurs] = createSignal(false);
1960
2029
  loadMeta().then(setMeta).catch(() => {});
1961
2030
  const refresh = async () => {
1962
2031
  try {
1963
2032
  const snapshot = await loadUsage();
2033
+ rememberSnapshot(snapshot);
1964
2034
  setUsage(usageRows(snapshot));
1965
2035
  const id = activeModelId();
1966
2036
  setModelUsage(id ? loadModelUsage(id, periodStart(snapshot)) ?? undefined : undefined);
1967
2037
  } catch {}
1968
2038
  };
1969
2039
  createEffect(() => {
1970
- if (!active())
2040
+ const kind = sessionKind(providerID());
2041
+ if (kind !== "ours")
1971
2042
  return;
2043
+ setWasOurs(true);
1972
2044
  refresh();
1973
2045
  const timer = setInterval(() => void refresh(), POLL_MS);
1974
2046
  onCleanup(() => clearInterval(timer));
1975
2047
  });
1976
2048
  return createMemo(() => {
1977
- if (!active())
2049
+ const kind = sessionKind(providerID());
2050
+ if (kind === "other")
2051
+ return [];
2052
+ if (kind === "unknown" && !wasOurs())
1978
2053
  return [];
1979
2054
  const id = activeModelId();
1980
2055
  const found = id ? meta().get(modelKey(id)) ?? meta().get(id) : undefined;
@@ -1989,13 +2064,13 @@ function useRows(activeModelId, active) {
1989
2064
 
1990
2065
  // src/tui.tsx
1991
2066
  var ID = "command-code.tui";
1992
- var isOurs = (providerID) => Boolean(providerID?.startsWith("command-code"));
2067
+ var themed = (colors) => loadPrefs().colors ? colors : mono(colors);
1993
2068
  function PanelV1(props) {
1994
2069
  const current = () => props.api.state.session.get(props.sessionID)?.model;
1995
- const rows = useRows(() => current()?.id, () => isOurs(current()?.providerID));
2070
+ const rows = useRows(() => current()?.id, () => current()?.providerID);
1996
2071
  return _$createComponent2(Panel, {
1997
2072
  rows,
1998
- colors: () => legacyColors(props.api.theme.current)
2073
+ colors: () => themed(legacyColors(props.api.theme.current))
1999
2074
  });
2000
2075
  }
2001
2076
  var tui = async (api) => {
@@ -2018,10 +2093,10 @@ function PanelV2(props) {
2018
2093
  ctx
2019
2094
  } = props;
2020
2095
  const current = () => ctx.data.session.get(props.sessionID)?.model;
2021
- const rows = useRows(() => current()?.id, () => isOurs(current()?.providerID));
2096
+ const rows = useRows(() => current()?.id, () => current()?.providerID);
2022
2097
  return _$createComponent2(Panel, {
2023
2098
  rows,
2024
- colors: () => hostColors(ctx.theme)
2099
+ colors: () => themed(hostColors(ctx.theme))
2025
2100
  });
2026
2101
  }
2027
2102
  var commandCodeTui = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
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",