31 // Fetch tracks, tasks, and weekly review in parallel
32 const [tracksResponse, tasksResponse, weeklyReviewResponse] = await Promise.all([
33 fetch('/api/tracks'),
34 fetch('/api/tasks'),
35 fetch(`/api/weekly-reviews/${weekNumber}`)
36 ]);
37
227
228 try {
229 const response = await fetch('/api/weekly-reviews', {
230 method: 'POST',
231 headers: {
250 // Send weekly email
251 try {
252 await fetch('/api/send-weekly-email', {
253 method: 'POST'
254 });
271
272 try {
273 const response = await fetch('/api/weekly-review-feedback', {
274 method: 'POST',
275 headers: {
81
82 try {
83 const response = await fetch('/api/user-status', {
84 method: 'POST',
85 headers: {
34 const fetchExistingLog = async () => {
35 try {
36 const response = await fetch(`/api/daily-logs/${date}`);
37
38 if (response.ok) {
111
112 try {
113 const response = await fetch('/api/daily-logs', {
114 method: 'POST',
115 headers: {
131 // Trigger email
132 try {
133 await fetch('/api/send-daily-email', {
134 method: 'POST'
135 });
156
157 try {
158 const response = await fetch('/api/daily-standup', {
159 method: 'POST'
160 });
30 try {
31 // Try to get user status
32 const response = await fetch('/api/user-status');
33
34 if (response.status === 404) {
56 try {
57 setIsLoading(true);
58 const response = await fetch('/api/migrate', {
59 method: 'POST',
60 headers: {
79 async function fetchInfo() {
80 try {
81 const response = await fetch('/api/info');
82 if (response.ok) {
83 const data = await response.json();
26 // Fetch track and tasks in parallel
27 const [trackResponse, tasksResponse] = await Promise.all([
28 fetch(`/api/tracks`),
29 fetch(`/api/tracks/${trackId}/tasks`)
30 ]);
31
55 const fetchTrackPrompt = async () => {
56 try {
57 const response = await fetch(`/api/tracks/${trackId}/prompt`);
58
59 if (response.ok) {
72
73 try {
74 const response = await fetch(`/api/tracks/${trackId}/guidance`, {
75 method: 'POST'
76 });
93 const handleTaskStatusChange = async (taskId, newStatus) => {
94 try {
95 const response = await fetch(`/api/tasks/${taskId}/status`, {
96 method: 'PUT',
97 headers: {
119 const handleTaskNotesChange = async (taskId, notes) => {
120 try {
121 const response = await fetch(`/api/tasks/${taskId}/notes`, {
122 method: 'PUT',
123 headers: {
145 const handleUpdateTrackStatus = async (newStatus) => {
146 try {
147 const response = await fetch(`/api/tracks/${trackId}`, {
148 method: 'PUT',
149 headers: {
170 const handlePromptUpdate = async () => {
171 try {
172 const response = await fetch(`/api/tracks/${trackId}/prompt`, {
173 method: 'PUT',
174 headers: {
33
34- ValTown SQLite for data storage
35- Hono framework for API endpoints
36- Vercel AI SDK for AI interactions using Gemini models
37- Val Town email service for notifications
524. Perform weekly reviews every Sunday
53
54## API Endpoints
55
56- `/api/migrate` - Run database migrations
57- `/api/tracks` - Get and update tracks
58- `/api/tasks` - Manage tasks
59- `/api/daily-logs` - Daily progress tracking
60- `/api/weekly-reviews` - Weekly strategic reviews
61- `/api/user-status` - Personal situation management
62- `/api/track-prompts` - Customizable AI prompts
63- `/api/quick-guidance` - Get immediate AI guidance
64- `/api/send-daily-email` - Trigger daily email notifications
65- `/api/send-weekly-email` - Trigger weekly email notifications
66
67## AI Guidance Features
80
81 try {
82 const response = await fetch('/api/user-status', {
83 method: 'POST',
84 headers: {
111 const handleSendEmail = async (type) => {
112 try {
113 const endpoint = type === 'daily' ? '/api/send-daily-email' : '/api/send-weekly-email';
114 const response = await fetch(endpoint, {
115 method: 'POST'
24 // Fetch tracks and tasks in parallel
25 const [tracksResponse, tasksResponse] = await Promise.all([
26 fetch('/api/tracks'),
27 fetch('/api/tasks')
28 ]);
29
48 const handleTaskStatusChange = async (taskId, newStatus) => {
49 try {
50 const response = await fetch(`/api/tasks/${taskId}/status`, {
51 method: 'PUT',
52 headers: {
74 const handleTaskNotesChange = async (taskId, notes) => {
75 try {
76 const response = await fetch(`/api/tasks/${taskId}/notes`, {
77 method: 'PUT',
78 headers: {
97
98export async function sendDailyBriefing(chatId?: string, today?: DateTime) {
99 // Get API keys from environment
100 const apiKey = Deno.env.get("ANTHROPIC_API_KEY");
101 const telegramToken = Deno.env.get("TELEGRAM_TOKEN");
102
106 }
107
108 if (!apiKey) {
109 console.error("Anthropic API key is not configured.");
110 return;
111 }
122
123 // Initialize Anthropic client
124 const anthropic = new Anthropic({ apiKey });
125
126 // Initialize Telegram bot
162
163 // disabled title for now, it seemes unnecessary...
164 // await bot.api.sendMessage(chatId, `*${title}*`, { parse_mode: "Markdown" });
165
166 // Then send the main content
169
170 if (content.length <= MAX_LENGTH) {
171 await bot.api.sendMessage(chatId, content, { parse_mode: "Markdown" });
172 // Store the briefing in chat history
173 await storeChatMessage(
198 // Send each chunk as a separate message and store in chat history
199 for (const chunk of chunks) {
200 await bot.api.sendMessage(chatId, chunk, { parse_mode: "Markdown" });
201 // Store each chunk in chat history
202 await storeChatMessage(
53You'll need to set up some environment variables to make it run.
54
55- `ANTHROPIC_API_KEY` for LLM calls
56- You'll need to follow [these instructions](https://docs.val.town/integrations/telegram/) to make a telegram bot, and set `TELEGRAM_TOKEN`. You'll also need to get a `TELEGRAM_CHAT_ID` in order to have the bot remember chat contents.
57- For the Google Calendar integration you'll need `GOOGLE_CALENDAR_ACCOUNT_ID` and `GOOGLE_CALENDAR_CALENDAR_ID`. See [these instuctions](https://www.val.town/v/stevekrouse/pipedream) for details.