codiedev 0.9.58 → 0.9.59

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.
@@ -31,6 +31,7 @@ const MARK = [
31
31
  const REFRESH_MS = 30_000
32
32
 
33
33
  const [usageLine, setUsageLine] = createSignal("")
34
+ const [usageTone, setUsageTone] = createSignal("normal")
34
35
 
35
36
  async function startUsagePolling() {
36
37
  let usage: any
@@ -56,7 +57,11 @@ async function startUsagePolling() {
56
57
  })
57
58
  // A failed poll leaves the last good line up rather than blanking it:
58
59
  // a number that stopped updating beats a number that vanished.
59
- if (snapshot) setUsageLine(usage.formatUsageLine(snapshot))
60
+ if (snapshot) {
61
+ setUsageLine(usage.formatUsageLine(snapshot))
62
+ // Older installs of the usage module have no tone; stay muted there.
63
+ if (typeof usage.usageTone === "function") setUsageTone(usage.usageTone(snapshot))
64
+ }
60
65
  } catch {}
61
66
  }
62
67
  void poll()
@@ -69,7 +74,14 @@ void startUsagePolling().catch(() => {})
69
74
 
70
75
  function StatusLine(props: { theme: any }) {
71
76
  return (
72
- <text fg={props.theme.textMuted} selectable={false}>
77
+ <text
78
+ fg={usageTone() === "critical"
79
+ ? (props.theme.error ?? props.theme.textMuted)
80
+ : usageTone() === "warn"
81
+ ? (props.theme.warning ?? props.theme.textMuted)
82
+ : props.theme.textMuted}
83
+ selectable={false}
84
+ >
73
85
  {usageLine()}
74
86
  </text>
75
87
  )
@@ -39,6 +39,13 @@ export interface CodieUsage {
39
39
  * Returns "" when there is nothing honest to say.
40
40
  */
41
41
  export declare function formatUsageLine(usage: CodieUsage | null | undefined): string;
42
+ export type UsageTone = "normal" | "warn" | "critical";
43
+ /**
44
+ * How urgently the status line should read, from the limit that will stop
45
+ * this developer first: their own cap, or the shared pool when they have no
46
+ * cap or the pool runs out sooner. 75% warns, 90% is critical.
47
+ */
48
+ export declare function usageTone(usage: CodieUsage | null | undefined): UsageTone;
42
49
  /**
43
50
  * What this session just cost. Returns "" when the session billed nothing,
44
51
  * because a developer who spent nothing does not need to be told a number.
@@ -9,6 +9,7 @@
9
9
  // delay, or break a coding session. No snapshot means no line.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.formatUsageLine = formatUsageLine;
12
+ exports.usageTone = usageTone;
12
13
  exports.formatSessionCostLine = formatSessionCostLine;
13
14
  exports.fetchCodieUsage = fetchCodieUsage;
14
15
  const USAGE_TIMEOUT_MS = 4000;
@@ -51,6 +52,16 @@ function formatUsageLine(usage) {
51
52
  const share = percent(budget.userSpentUsd, budget.userBudgetUsd);
52
53
  if (share)
53
54
  segments.push(share);
55
+ // A personal cap does not help once the shared pool is nearly gone: say
56
+ // so when the pool is running low and will stop this developer before
57
+ // their own cap does.
58
+ if (poolBindsFirst(budget) && typeof budget.companyBudgetUsd === "number"
59
+ && budget.companyBudgetUsd > 0
60
+ && budget.companySpentUsd / budget.companyBudgetUsd >= 0.75) {
61
+ const share = percent(budget.companySpentUsd, budget.companyBudgetUsd);
62
+ if (share)
63
+ segments.push(`team pool ${share}`);
64
+ }
54
65
  }
55
66
  else {
56
67
  segments.push(money(budget.userSpentUsd));
@@ -62,6 +73,10 @@ function formatUsageLine(usage) {
62
73
  segments.push(`team ${share}`);
63
74
  }
64
75
  }
76
+ if (typeof budget.companyBudgetUsd === "number" && budget.companyBudgetUsd > 0
77
+ && budget.companySpentUsd >= budget.companyBudgetUsd) {
78
+ segments.push("team pool used up");
79
+ }
65
80
  if (inFlight.requests > 0)
66
81
  segments.push(`${inFlight.requests} in flight`);
67
82
  // Stale holds cap a budget while doing no work. Naming them is the
@@ -70,6 +85,37 @@ function formatUsageLine(usage) {
70
85
  segments.push(`${money(inFlight.staleHeldUsd)} held stale`);
71
86
  return segments.join(" · ");
72
87
  }
88
+ function poolBindsFirst(budget) {
89
+ if (typeof budget.companyBudgetUsd !== "number" || typeof budget.userBudgetUsd !== "number")
90
+ return false;
91
+ const poolLeft = Math.max(0, budget.companyBudgetUsd - budget.companySpentUsd);
92
+ const userLeft = Math.max(0, budget.userBudgetUsd - budget.userSpentUsd);
93
+ return budget.userBudgetUsd > 0 && poolLeft < userLeft;
94
+ }
95
+ /**
96
+ * How urgently the status line should read, from the limit that will stop
97
+ * this developer first: their own cap, or the shared pool when they have no
98
+ * cap or the pool runs out sooner. 75% warns, 90% is critical.
99
+ */
100
+ function usageTone(usage) {
101
+ if (!usage || !usage.enabled)
102
+ return "normal";
103
+ const { budget } = usage;
104
+ const ratios = [];
105
+ if (typeof budget.userBudgetUsd === "number" && budget.userBudgetUsd > 0) {
106
+ ratios.push(budget.userSpentUsd / budget.userBudgetUsd);
107
+ }
108
+ if (typeof budget.companyBudgetUsd === "number" && budget.companyBudgetUsd > 0
109
+ && (typeof budget.userBudgetUsd !== "number" || poolBindsFirst(budget))) {
110
+ ratios.push(budget.companySpentUsd / budget.companyBudgetUsd);
111
+ }
112
+ const worst = ratios.length ? Math.max(...ratios) : 0;
113
+ if (worst >= 0.9)
114
+ return "critical";
115
+ if (worst >= 0.75)
116
+ return "warn";
117
+ return "normal";
118
+ }
73
119
  function tokens(total) {
74
120
  // Rounded by arithmetic, not toFixed: 2.55 is not exactly representable, so
75
121
  // toFixed(1) rounds it down and the same count can read two ways.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.58",
3
+ "version": "0.9.59",
4
4
  "description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",