Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ The renderer is **never type-checked by Vite** (esbuild strips types). `npm run

---

## Visual verification (Claude Code)

The app supports visual feedback via Chrome DevTools Protocol during development.

### Verify and connect

```bash
curl -s http://localhost:9333/json/version # should return Electron/Chrome JSON
agent-browser connect 9333
agent-browser screenshot /tmp/screenshot.png
agent-browser snapshot -i # DOM inspection
```

### Workflow

After making UI changes:

1. `npm run dev` (CDP already enabled)
2. `agent-browser connect 9333`
3. `agent-browser screenshot /tmp/tt2-screenshot.png`
4. Inspect the screenshot and fix any rendering issues before committing

---

## Architecture

### IPC bridge
Expand Down Expand Up @@ -122,7 +146,7 @@ Main process (`src/`), IPC handlers, WebSocket bootstrap, auth flow, and most ho

- **`globals.d.ts` must stay ambient** — no `export {}`, no `import`. Adding either makes it a module and breaks global type resolution silently in the renderer.
- **Renderer typecheck is separate** — `tsc` at the root only checks `src/`. Always run `npm run typecheck` (which checks both) not just `tsc`.
- **`applyReorderLocally` index math** — `insertAt` is the count of non-selected items whose *original* index is less than `toIndex`, not `toIndex` itself. See `queueHelpers.ts` for comments.
- **`applyReorderLocally` index math** — `insertAt` is the count of non-selected items whose _original_ index is less than `toIndex`, not `toIndex` itself. See `queueHelpers.ts` for comments.
- **Image cache is a singleton module** — tests that import `imageCache` must use `vi.resetModules()` and dynamic `import()` in `beforeEach` to avoid state leaking between tests.
- **Sandbox mode** — both `uiWin` and `miniWin` have `sandbox: true`. The preload script runs in the sandboxed context; do not use Node.js APIs directly in `preload.ts`.
- **Debug windows are intentionally insecure** — `nodeIntegration: true` on the WS/HTTP debug windows is by design and guarded by `app.isPackaged` check. Do not "fix" this.
Expand All @@ -133,13 +157,13 @@ Main process (`src/`), IPC handlers, WebSocket bootstrap, auth flow, and most ho

Resource group: `truetunes-rg` (uksouth)

| Resource | Name |
|---|---|
| Function App | `truetunes-fn` |
| Web PubSub | `truetunes-wps` |
| Cosmos DB | `truetunes-cosmos` |
| Storage | `truetunesfoywo62izs34i` |
| App Insights | `truetunes-ai` |
| Log Analytics | `truetunes-law` |
| Resource | Name |
| ------------- | ------------------------ |
| Function App | `truetunes-fn` |
| Web PubSub | `truetunes-wps` |
| Cosmos DB | `truetunes-cosmos` |
| Storage | `truetunesfoywo62izs34i` |
| App Insights | `truetunes-ai` |
| Log Analytics | `truetunes-law` |

Deploy: `cd server && npm run deploy` — wraps `az deployment group create` and reads `VESTABOARD_API_KEY` from the root `.env`, passing it as the `vestaboardApiKey` ARM parameter so the secret is never committed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
},
"main": "dist/main.js",
"scripts": {
"build:main": "tsc && node -e \"const fs=require('fs');fs.copyFileSync('src/debug-ws.html','dist/debug-ws.html');fs.copyFileSync('src/debug-http.html','dist/debug-http.html')\"",
"build:main": "tsc && node -e \"const fs=require('fs');fs.copyFileSync('src/debug-ws.html','dist/debug-ws.html');fs.copyFileSync('src/debug-http.html','dist/debug-http.html');fs.writeFileSync('dist/build-env.json',JSON.stringify({GENIUS_ACCESS_TOKEN:process.env.GENIUS_ACCESS_TOKEN||'',APPINSIGHTS_CONNECTION_STRING:process.env.APPINSIGHTS_CONNECTION_STRING||''}))\"",
"build:renderer": "vite build --config renderer/vite.config.ts",
"build": "npm run build:main && npm run build:renderer",
"dev:renderer": "vite --config renderer/vite.config.ts",
"dev": "npm run build:main && concurrently -k \"npm run dev:renderer\" \"electron .\"",
"dev": "npm run build:main && concurrently -k \"npm run dev:renderer\" \"electron . --remote-debugging-port=9333\"",
"start": "npm run build && electron .",
"electron:build": "npm run build && electron-builder",
"electron:build:win": "npm run build && electron-builder --win",
Expand Down
9 changes: 9 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import { autoUpdater } from 'electron-updater';
import { officePubSub } from './pubsub';
import * as path from 'path';
import * as fs from 'fs/promises';
import { readFileSync } from 'fs';

// Load secrets baked in at build time — fills gaps that dotenv didn't cover (packaged app has no .env)
try {
const baked = JSON.parse(readFileSync(path.join(__dirname, 'build-env.json'), 'utf8')) as Record<string, string>;
for (const [k, v] of Object.entries(baked)) {
if (v && !process.env[k]) process.env[k] = v;
}
} catch { /* dev: dotenv already handled it */ }
import { randomUUID } from 'crypto';
import WebSocket from 'ws';
import type { FetchRequest, FetchResponse } from './types';
Expand Down
Loading