@promptctl/cc-candybar 1.13.0 → 1.15.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptctl/cc-candybar",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "Statusline renderer for Claude Code — a JSON5-configurable DSL with daemon-cached data sources, byte-clean palette-aware composition, and OSC8 click verbs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -91,10 +91,10 @@
91
91
  "mobx": "^6.15.0"
92
92
  },
93
93
  "optionalDependencies": {
94
- "@promptctl/cc-candybar-darwin-arm64": "1.13.0",
95
- "@promptctl/cc-candybar-darwin-x64": "1.13.0",
96
- "@promptctl/cc-candybar-linux-x64": "1.13.0",
97
- "@promptctl/cc-candybar-linux-arm64": "1.13.0"
94
+ "@promptctl/cc-candybar-darwin-arm64": "1.15.0",
95
+ "@promptctl/cc-candybar-darwin-x64": "1.15.0",
96
+ "@promptctl/cc-candybar-linux-x64": "1.15.0",
97
+ "@promptctl/cc-candybar-linux-arm64": "1.15.0"
98
98
  },
99
99
  "pnpm": {
100
100
  "supportedArchitectures": {
@@ -51,12 +51,24 @@ import type { DslConfig } from "./dsl-types.js";
51
51
  // (project_dir), so the project root renders as `<repo-name>` instead of the
52
52
  // full absolute path. Same logic handles equal home & current_dir → just "~".
53
53
  const DIR_REL = 'trimPrefix "/" (trimPrefix .project_dir .current_dir)';
54
+ // [LAW:decomposition] Two separable concerns: (1) COLLAPSE the absolute cwd to a
55
+ // short display form (`~`-relative, else project-relative, else absolute) and
56
+ // (2) ABBREVIATE fish-style. Collapse stays in the template (its inputs are the
57
+ // payload's home/project_dir/current_dir); abbreviation is a single helper
58
+ // applied to the collapsed result. `$dir` carries the collapsed path between the
59
+ // two — default is the absolute cwd, overridden only when it lives under home or
60
+ // the project root. brandon-directory-781 makes fish-abbreviation the DEFAULT;
61
+ // a user restores the full path by overriding `segments.directory.template`
62
+ // (drop the `abbreviatePath` wrapper) — the existing merge-by-name seam.
54
63
  const DIR_TEMPLATE =
55
- '{{ if and (ne .home "") (or (eq .home .current_dir) (hasPrefix (printf "%s/" .home) .current_dir)) }}~{{ trimPrefix .home .current_dir }}' +
64
+ "{{ $dir := .current_dir }}" +
65
+ '{{ if and (ne .home "") (or (eq .home .current_dir) (hasPrefix (printf "%s/" .home) .current_dir)) }}' +
66
+ `{{ $dir = printf "~%s" (trimPrefix .home .current_dir) }}` +
56
67
  "{{ else }}" +
57
68
  '{{ if or (eq .project_dir .current_dir) (hasPrefix (printf "%s/" .project_dir) .current_dir) }}' +
58
- `{{ ternary (${DIR_REL}) (basename .project_dir) (ne (${DIR_REL}) "") }}` +
59
- "{{ else }}{{ .current_dir }}{{ end }}{{ end }}";
69
+ `{{ $dir = ternary (${DIR_REL}) (basename .project_dir) (ne (${DIR_REL}) "") }}` +
70
+ "{{ end }}{{ end }}" +
71
+ "{{ abbreviatePath $dir }}";
60
72
 
61
73
  // Git working-tree counts — leading-space-then-trim idiom: each present count
62
74
  // contributes " +N", trim drops the leading space, survivors single-spaced.
@@ -318,6 +330,15 @@ export const DEFAULT_DSL_CONFIG = {
318
330
  type: "number",
319
331
  default: 0,
320
332
  },
333
+ // Budget knobs — pure config constants, user overrides in their file.
334
+ // [LAW:dataflow-not-control-flow] amount defaults 0, the budgetStatus
335
+ // helper's non-displayable value, so with no user override the session
336
+ // segment renders byte-identically to its pre-budget form through the
337
+ // same unconditional template — opt-in is a value, not a config mode.
338
+ // Matches the legacy shipped default (budget.session had a threshold but
339
+ // no amount ⇒ suffix off until the user sets an amount).
340
+ "session.budget.amount": { kind: "literal", value: 0 },
341
+ "session.budget.warningThreshold": { kind: "literal", value: 80 },
321
342
 
322
343
  // Today — daemon folds today's cross-session total from the SessionUsageStore.
323
344
  "today.cost": {
@@ -609,7 +630,8 @@ export const DEFAULT_DSL_CONFIG = {
609
630
  },
610
631
  session: {
611
632
  template:
612
- '§ {{ template "formatCost" .session.cost }} ({{ template "formatTokens" .session.tokens }})',
633
+ '§ {{ template "formatCost" .session.cost }} ({{ template "formatTokens" .session.tokens }})' +
634
+ '{{ template "budgetStatus" (dict "cost" .session.cost "budget" .session.budget.amount "warn" .session.budget.warningThreshold) }}',
613
635
  bg: "surface",
614
636
  fg: "foreground",
615
637
  },
@@ -12,6 +12,7 @@ import {
12
12
  type VarValue,
13
13
  } from "../var-system/types.js";
14
14
  import {
15
+ abbreviatePath,
15
16
  formatInteger,
16
17
  formatModelName,
17
18
  shortenModelName,
@@ -63,6 +64,15 @@ export function ccCandybarFuncs(): FuncMap {
63
64
  argTypes: ["string"],
64
65
  },
65
66
 
67
+ // [LAW:decomposition] Fish-style path abbreviation — one thing: shorten
68
+ // every segment but the leaf. Composes over the directory template's
69
+ // already-collapsed output (`~`/project-relative), never duplicating that
70
+ // logic. Impl in utils/formatters.ts, mirroring formatModelName's split.
71
+ abbreviatePath: {
72
+ fn: (s: string) => abbreviatePath(s),
73
+ argTypes: ["string"],
74
+ },
75
+
66
76
  // [LAW:single-enforcer] Type casts delegate to var-system/types.ts.
67
77
  // "value" argType: these funcs enforce their own constraints and emit
68
78
  // a useful TypeError on ambiguous input — no need for the engine gate
@@ -63,6 +63,28 @@ export function shortenModelName(formatted: string): string {
63
63
  return `${initial}${version}`;
64
64
  }
65
65
 
66
+ // [LAW:decomposition] Fish-shell `prompt_pwd` abbreviation: collapse every path
67
+ // segment EXCEPT the leaf to its leading character, keeping any leading dots so
68
+ // `.config` → `.c`. A pure string→string transform that knows nothing about
69
+ // home-collapse or project-relative logic — those live in the directory
70
+ // template and this abbreviates whatever collapsed display path they produce.
71
+ // `~/code/cc-candybar` → `~/c/cc-candybar`; a leading "/" is preserved because
72
+ // the empty pre-slash segment abbreviates to empty (`/usr/local/bin` → `/u/l/bin`).
73
+ export function abbreviatePath(path: string): string {
74
+ const segments = path.split("/");
75
+ const lastIndex = segments.length - 1;
76
+ return segments
77
+ .map((seg, i) => {
78
+ if (i === lastIndex) return seg;
79
+ // Leading dot-run plus the first following char (fish keeps dotfiles
80
+ // legible: `.config` → `.c`, `..` → `..`). No following char (empty
81
+ // segment) means no match — return it unchanged.
82
+ const abbreviated = seg.match(/^\.*./);
83
+ return abbreviated ? abbreviated[0] : seg;
84
+ })
85
+ .join("/");
86
+ }
87
+
66
88
  // [LAW:one-source-of-truth] Locale-grouped integer rendering. Callers that
67
89
  // want "50,000" instead of "50000" go through this rather than calling
68
90
  // toLocaleString() ad-hoc — the legacy context segment used the latter