From 15ecb7879748b61919484e2faf094b350e4c1d4f Mon Sep 17 00:00:00 2001
From: Vimox Shah <10022243+vimoxshah@users.noreply.github.com>
Date: Mon, 14 Sep 2026 11:41:11 +0530
Subject: [PATCH 1/2] fix(test): skip the app-bundle suite on a Mac that cannot
compile SwiftUI
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The suite skipped when `swiftc` was absent, which is not the condition that
matters. The Command Line Tools ship `swiftc` but not SwiftUI's macro plugins,
so on a Mac with no Xcode `@State` never expands and every view in main.swift
collapses into errors about assigning to an immutable `self`. Three tests
failed, and the failure read as a defect in the menu bar app rather than a
missing toolchain.
The probe now compiles the smallest view that needs the plugin, and the skip
message names Xcode.
Also: the README said 836 tests where the suite has 841, and its link row
printed `brew install --cask tokenflow` on its own, which fails — the cask
lives in this repo's own tap, so the tap command has to come first. The row
points at the Install section, which carries both lines.
Co-Authored-By: Claude Opus 5 (1M context)
---
README.md | 6 +++---
test/bundle.test.js | 18 ++++++++++++++----
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index 0f18149..e53b82a 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ per-source and per-model usage, capacity meters and forecast, in light and dark.
·
📦 @vimoxshah/tokenflow on npm
·
- 🍺 brew install --cask tokenflow (via this tap)
+ 🍺 Homebrew (tap, then cask)
**How deep it goes**
@@ -62,7 +62,7 @@ per-source and per-model usage, capacity meters and forecast, in light and dark.
| **Analytics** | 21 views: overview KPIs with a story strip, receipts per branch and pull request, cost per ticket, session anatomy, live, composition, provider/model intelligence, interfaces, hour×weekday heatmap + calendar, peaks, efficiency ratios, cache health, cost with coverage, model what-if, git correlations (labelled), rhythm and focus, period compare, compare branches, searchable data explorer, annotations, per-field data health |
| **Integrations** | A GitHub Action and a **self-hosted GitHub App** (your App, your server, our code) that put a receipt comment and a budget check run on every pull request; receipts as git notes that travel with the code; an **MCP server** so the agent can read its own bill; a **FOCUS-shaped export** for a FinOps tool; **org policy** pulled from a team server you run |
| **Live mode** | Watcher daemon, native Swift menu bar app (live sessions, today's receipts, guard state, provider/source/model breakdowns, capacity meters with reset countdowns & ETAs, forecast with stated confidence, MAD-based anomaly alerts, per-source sparklines, appearance toggle), SwiftBar/xbar plugin |
-| **Engineering** | Zero runtime dependencies · 836 tests · lint invariants (e.g. "no `\|\| 0` on a token field") · tsc-clean JSDoc types · CI on macOS/Linux/Windows × Node 22/24 |
+| **Engineering** | Zero runtime dependencies · 841 tests · lint invariants (e.g. "no `\|\| 0` on a token field") · tsc-clean JSDoc types · CI on macOS/Linux/Windows × Node 22/24 |
Zero runtime dependencies. Nothing leaves your machine. No API keys, no accounts, no telemetry.
@@ -332,7 +332,7 @@ from `file://` with no server. A full CSV export doubles as a portable dataset:
## Contributing
```bash
-npm test # 836 tests: normalization, adapters, analytics, store, receipts, guard
+npm test # 841 tests: normalization, adapters, analytics, store, receipts, guard
npm run lint # project invariants (incl. "no || 0 on a token field")
npm run typecheck # tsc over JSDoc types — must be zero errors
npm run validate # self-check: runtime, adapters, store↔cube agreement
diff --git a/test/bundle.test.js b/test/bundle.test.js
index 7a0cb83..7906e36 100644
--- a/test/bundle.test.js
+++ b/test/bundle.test.js
@@ -14,22 +14,32 @@ import { execFileSync } from 'node:child_process';
* had a menu bar app with nothing to drive. Both are build-script properties,
* invisible to every other test, and only a real build can prove them.
*
- * Building takes swiftc, so this suite skips anywhere it cannot run: off
- * macOS, or on a macOS box without the Command Line Tools.
+ * Building takes a toolchain that can compile SwiftUI, so this suite skips
+ * anywhere it cannot run. `swiftc --version` is not that test: the Command Line
+ * Tools ship swiftc but not SwiftUI's macro plugins, so on a Mac with no Xcode
+ * `@State` fails to expand and every view in main.swift collapses into errors
+ * about assigning to an immutable self. That reads as a product defect and is
+ * not one, so the probe below compiles the smallest thing that needs the
+ * plugin and skips when it cannot.
*/
const REPO = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), '..');
function canBuild() {
if (process.platform !== 'darwin') return false;
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tf-swift-probe-'));
+ const file = path.join(dir, 'probe.swift');
try {
- execFileSync('swiftc', ['--version'], { stdio: 'ignore', timeout: 20000 });
+ fs.writeFileSync(file, 'import SwiftUI\nstruct P: View { @State private var x = 0\n var body: some View { Color.clear.onHover { _ in x = 1 } } }\n');
+ execFileSync('swiftc', ['-typecheck', file], { stdio: 'ignore', timeout: 120000 });
return true;
} catch {
return false;
+ } finally {
+ fs.rmSync(dir, { recursive: true, force: true });
}
}
-const skip = canBuild() ? false : 'needs macOS with swiftc';
+const skip = canBuild() ? false : 'needs macOS with a toolchain that can compile SwiftUI (Xcode, not the Command Line Tools alone)';
function build(outDir, { portable }) {
execFileSync('bash', [path.join(REPO, 'scripts', 'build-menubar-app.sh'), outDir], {
From 42cdc71e989c2cddb877684ce6619118ef196a3c Mon Sep 17 00:00:00 2001
From: Vimox Shah <10022243+vimoxshah@users.noreply.github.com>
Date: Mon, 14 Sep 2026 11:41:28 +0530
Subject: [PATCH 2/2] chore(release): 1.3.5
Co-Authored-By: Claude Opus 5 (1M context)
---
CHANGELOG.md | 23 +++++++++++++++++++++++
action/README.md | 2 +-
docs/receipts-on-github.md | 2 +-
package.json | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b413ba2..c2147a7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,29 @@
All notable changes to TokenFlow are recorded here. Versions follow
[semantic versioning](https://semver.org/spec/v2.0.0.html).
+## 1.3.5 — 2026-09-14
+
+No change to how TokenFlow reads or prices anything. One test-suite defect and two
+documentation corrections.
+
+### Fixed
+
+- **`npm test` no longer fails on a Mac without Xcode.** The app-bundle suite skipped when
+ `swiftc` was absent, which is not the condition that matters: the Command Line Tools ship
+ `swiftc` but not SwiftUI's macro plugins, so `@State` never expands and every view in
+ `main.swift` collapses into errors about assigning to an immutable `self`. Three tests
+ failed, and the failure read as a defect in the menu bar app rather than a missing toolchain.
+ The probe now compiles the smallest view that needs the plugin, and the skip message names
+ Xcode. The shipped app is unaffected: CI builds it on a runner with the full toolchain.
+
+### Docs
+
+- **The test count reads 841**, which is what the suite has. The README said 836.
+- **The README's link row no longer prints half the Homebrew command.** `brew install --cask
+ tokenflow` on its own fails, because the cask lives in this repo's own tap and the tap
+ command has to come first. The row now points at the Install section, which carries both
+ lines.
+
## 1.3.4 — 2026-09-07
Interface fixes only; nothing about how TokenFlow reads or prices usage changes. Every one of
diff --git a/action/README.md b/action/README.md
index fe14fd6..b7cc04b 100644
--- a/action/README.md
+++ b/action/README.md
@@ -34,7 +34,7 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # notes live outside the default shallow fetch
- - uses: vimoxshah/tokenflow@v1.3.4
+ - uses: vimoxshah/tokenflow@v1.3.5
# or, dogfooding this repo's own checkout: uses: ./
with:
token: ${{ secrets.GITHUB_TOKEN }} # default; only pass to override
diff --git a/docs/receipts-on-github.md b/docs/receipts-on-github.md
index 1cd0855..22e13ec 100644
--- a/docs/receipts-on-github.md
+++ b/docs/receipts-on-github.md
@@ -44,7 +44,7 @@ network call.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # notes live outside the default shallow fetch
- - uses: vimoxshah/tokenflow@v1.3.4
+ - uses: vimoxshah/tokenflow@v1.3.5
with:
max-usd: '50'
max-usd-per-100-lines: '5'
diff --git a/package.json b/package.json
index 44fd017..e532c8b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@vimoxshah/tokenflow",
- "version": "1.3.4",
+ "version": "1.3.5",
"description": "Local-first, provider-agnostic analytics for the AI tokens you actually spend. Zero dependencies, nothing leaves your machine.",
"type": "module",
"license": "MIT",