35: `applications/${DISCORD_APP_ID}/commands`;
3637console.log(`📡 Using API endpoint: ${endpoint}`);
3839try {
41console.log("🔍 Checking current commands...");
4243const getResponse = await fetch(`https://discord.com/api/v10/${endpoint}`, {
44method: "GET",
45headers: {
6263// Send empty array to unregister all commands
64const response = await fetch(`https://discord.com/api/v10/${endpoint}`, {
65method: "PUT",
66headers: {
9- **File Browser**: Select specific files to include in the context window for more focused AI assistance
10- **Branch Management**: View, select, and create branches without leaving the app
11- **Cost Tracking**: See estimated API usage costs for each interaction
12- **Sound Notifications**: Get alerted when Claude finishes responding
13- **Mobile-Friendly**: Works on both desktop and mobile devices
14- **Usage Dashboard**: Monitor API usage and inference calls with detailed analytics
1516## How It Works
17181. **Login**: Authenticate with your Val Town API token and Anthropic API key
192. **Select a Project**: Choose which Val Town project you want to work on
203. **Select Files**: Browse your project files and select which ones to include in the context window
26### Prerequisites
2728- A Val Town account with API access
29- An Anthropic API key (Claude 3.7 Sonnet)
3031### Setup
32331. Visit the OpenTownie app
342. Enter your Val Town API token (with `projects:write` and `users:read` permissions)
353. Enter your Anthropic API key
364. Click "Login" to access your projects
3749- React frontend with TypeScript
50- React Router
51- Hono API server backend
52- Web Audio API for sound notifications
53- AI SDK for Claude integration
5455The application proxies requests to the Anthropic API and Val Town API, allowing Claude to view and edit your project files directly.
5657## Privacy & Security
5859- Your Val Town API token and Anthropic API key are stored locally in your browser
60- No data is stored on our servers
61- All communication with the APIs is done directly from your browser
62
Townieschema.tsx2 matches
19finish_reason?: string;
20num_images?: number;
21our_api_token: boolean;
22}
2344finish_reason TEXT,
45num_images INTEGER,
46our_api_token INTEGER NOT NULL,
47finish_timestamp INTEGER
48)
Townieuser-summary.ts1 match
20SUM(num_images) as total_images
21FROM ${USAGE_TABLE}
22WHERE our_api_token = 1
23GROUP BY user_id, username
24ORDER BY total_price DESC
Townierequests.ts4 matches
17finish_reason: string | null;
18num_images: number | null;
19our_api_token: number;
20}
2157
58// Fetch the inference calls data
59fetch('/api/inference-calls?usage_id=' + usageId)
60.then(response => response.json())
61.then(data => {
192<th>Finish</th>
193<th>Images</th>
194<th>Our API</th>
195</tr>
196</thead>
216<td>${row.finish_reason || '-'}</td>
217<td>${formatNumber(row.num_images)}</td>
218<td>${formatBoolean(row.our_api_token)}</td>
219</tr>
220`).join("")}
1# Usage Dashboard
23A dashboard for monitoring API usage and inference calls.
45## Features
20index.ts # Main entry point and routing
21auth.ts # Authentication logic
22/api/
23index.ts # API request handler
24requests.ts # API endpoints for requests data
25inference-calls.ts # API endpoints for inference calls
26user-summary.ts # API endpoints for user summary data
27/views/
28layout.ts # Common layout template
54- Links back to the associated request
5556### API Endpoints
5758- `/api/requests` - Get paginated requests
59- `/api/requests?usage_id=123` - Get a specific request
60- `/api/inference-calls` - Get paginated inference calls
61- `/api/inference-calls?usage_id=123` - Get inference calls for a specific request
62- `/api/user-summary` - Get user summary data
6364## Debugging
1import { basicAuthMiddleware } from "./auth.ts";
2import { handleApiRequest } from "./api/index.ts";
3import { getRequests } from "./api/requests.ts";
4import { getUserSummary } from "./api/user-summary.ts";
5import { getInferenceCalls } from "./api/inference-calls.ts";
6import { renderDashboard } from "./views/dashboard.ts";
7import { renderRequests } from "./views/requests.ts";
22const path = url.pathname;
2324// Handle API requests
25if (path.startsWith("/api/")) {
26return handleApiRequest(req);
27}
28
45/**
6* Handle API requests
7*/
8export async function handleApiRequest(req: Request): Promise<Response> {
9const url = new URL(req.url);
10const path = url.pathname.replace("/api/", "");
11
12try {
13// Route to the appropriate API handler
14if (path === "requests") {
15const usageId = url.searchParams.get("usage_id");
59}
60} catch (error) {
61console.error("API error:", error);
62return new Response(JSON.stringify({ error: error.message }), {
63status: 500,
GitHub-Release-Notestypes.ts1 match
1// GitHub API response types
2export interface GitHubCommit {
3sha: string;
GitHub-Release-Notesindex.tsx3 matches
45
46try {
47const response = await fetch(`/api/share/${shareId}`);
48const data = await response.json();
49
80
81try {
82const response = await fetch("/api/commits", {
83method: "POST",
84headers: {
119
120try {
121const response = await fetch("/api/generate-notes", {
122method: "POST",
123headers: {