@telemetryos/cli 1.7.5 → 1.8.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.
Files changed (23) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/commands/init.js +11 -0
  3. package/dist/services/generate-application.d.ts +1 -0
  4. package/dist/services/generate-application.js +127 -4
  5. package/dist/utils/validate-project-name.d.ts +19 -0
  6. package/dist/utils/validate-project-name.js +44 -0
  7. package/package.json +2 -2
  8. package/templates/vite-react-typescript/CLAUDE.md +68 -1244
  9. package/templates/vite-react-typescript/_claude/settings.local.json +17 -0
  10. package/templates/vite-react-typescript/_claude/skills/tos-architecture/SKILL.md +313 -0
  11. package/templates/vite-react-typescript/_claude/skills/tos-debugging/SKILL.md +299 -0
  12. package/templates/vite-react-typescript/_claude/skills/tos-media-api/SKILL.md +335 -0
  13. package/templates/vite-react-typescript/_claude/skills/tos-proxy-fetch/SKILL.md +319 -0
  14. package/templates/vite-react-typescript/_claude/skills/tos-render-design/SKILL.md +332 -0
  15. package/templates/vite-react-typescript/_claude/skills/tos-requirements/SKILL.md +252 -0
  16. package/templates/vite-react-typescript/_claude/skills/tos-settings-ui/SKILL.md +636 -0
  17. package/templates/vite-react-typescript/_claude/skills/tos-store-sync/SKILL.md +359 -0
  18. package/templates/vite-react-typescript/_claude/skills/tos-weather-api/SKILL.md +384 -0
  19. package/templates/vite-react-typescript/src/views/Render.css +1 -1
  20. package/templates/vite-react-typescript/src/views/Render.tsx +1 -1
  21. package/templates/vite-react-typescript/src/views/Settings.tsx +2 -2
  22. package/templates/vite-react-typescript/AGENTS.md +0 -7
  23. /package/templates/vite-react-typescript/{gitignore → _gitignore} +0 -0
@@ -0,0 +1,384 @@
1
+ ---
2
+ name: tos-weather-api
3
+ description: Integrate TelemetryOS Weather API for current conditions and forecasts. Use when building weather displays or any app that needs location-based weather data.
4
+ ---
5
+
6
+ # TelemetryOS Weather API
7
+
8
+ The Weather API provides current conditions, hourly forecasts, and daily forecasts for any location.
9
+
10
+ ## Quick Reference
11
+
12
+ ```typescript
13
+ import { weather } from '@telemetryos/sdk'
14
+
15
+ // Current conditions
16
+ const conditions = await weather().getConditions({
17
+ city: 'New York',
18
+ units: 'imperial'
19
+ })
20
+
21
+ // Hourly forecast (next 24 hours)
22
+ const hourly = await weather().getHourlyForecast({
23
+ city: 'New York',
24
+ units: 'imperial',
25
+ hours: 24
26
+ })
27
+
28
+ // Daily forecast (next 7 days)
29
+ const daily = await weather().getDailyForecast({
30
+ city: 'New York',
31
+ units: 'imperial',
32
+ days: 7
33
+ })
34
+ ```
35
+
36
+ ## Location Parameters
37
+
38
+ Specify location using ONE of these methods:
39
+
40
+ ### By City Name
41
+
42
+ ```typescript
43
+ // City only
44
+ { city: 'New York' }
45
+
46
+ // City with country
47
+ { city: 'London, UK' }
48
+
49
+ // City with state (US)
50
+ { city: 'Portland, OR' }
51
+ ```
52
+
53
+ ### By Postal Code
54
+
55
+ ```typescript
56
+ { postalCode: '10001' }
57
+ ```
58
+
59
+ ### By Coordinates
60
+
61
+ ```typescript
62
+ { lat: '40.7128', lon: '-74.0060' }
63
+ ```
64
+
65
+ ## Units
66
+
67
+ ```typescript
68
+ // Fahrenheit, miles, etc.
69
+ { units: 'imperial' }
70
+
71
+ // Celsius, kilometers, etc.
72
+ { units: 'metric' }
73
+ ```
74
+
75
+ ## Response Types
76
+
77
+ ### WeatherConditions (Current)
78
+
79
+ ```typescript
80
+ interface WeatherConditions {
81
+ EpochTime: number
82
+ WeatherText: string
83
+ WeatherIcon: number
84
+ HasPrecipitation: boolean
85
+ PrecipitationType: string | null
86
+ IsDayTime: boolean
87
+ Temperature: {
88
+ Metric: { Value: number; Unit: string }
89
+ Imperial: { Value: number; Unit: string }
90
+ }
91
+ RealFeelTemperature: {
92
+ Metric: { Value: number; Unit: string }
93
+ Imperial: { Value: number; Unit: string }
94
+ }
95
+ RelativeHumidity: number
96
+ Wind: {
97
+ Direction: { Degrees: number; English: string }
98
+ Speed: {
99
+ Metric: { Value: number; Unit: string }
100
+ Imperial: { Value: number; Unit: string }
101
+ }
102
+ }
103
+ UVIndex: number
104
+ UVIndexText: string
105
+ Visibility: {
106
+ Metric: { Value: number; Unit: string }
107
+ Imperial: { Value: number; Unit: string }
108
+ }
109
+ CloudCover: number
110
+ Pressure: {
111
+ Metric: { Value: number; Unit: string }
112
+ Imperial: { Value: number; Unit: string }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### WeatherForecast (Hourly/Daily)
118
+
119
+ ```typescript
120
+ interface WeatherForecast {
121
+ DateTime: string
122
+ EpochDateTime: number
123
+ WeatherIcon: number
124
+ IconPhrase: string
125
+ HasPrecipitation: boolean
126
+ PrecipitationType?: string
127
+ PrecipitationIntensity?: string
128
+ IsDaylight: boolean
129
+ Temperature: {
130
+ Value: number
131
+ Unit: string
132
+ }
133
+ RealFeelTemperature: {
134
+ Value: number
135
+ Unit: string
136
+ }
137
+ Wind: {
138
+ Speed: { Value: number; Unit: string }
139
+ Direction: { Degrees: number; English: string }
140
+ }
141
+ RelativeHumidity: number
142
+ PrecipitationProbability: number
143
+ }
144
+ ```
145
+
146
+ ## Complete Example
147
+
148
+ ### Settings (City + Units Selection)
149
+
150
+ ```typescript
151
+ // hooks/store.ts
152
+ import { createUseInstanceStoreState } from '@telemetryos/sdk/react'
153
+
154
+ export const useCityState = createUseInstanceStoreState<string>('city', '')
155
+ export const useUnitsState = createUseInstanceStoreState<'imperial' | 'metric'>('units', 'imperial')
156
+ ```
157
+
158
+ ```typescript
159
+ // views/Settings.tsx
160
+ import {
161
+ SettingsContainer,
162
+ SettingsField,
163
+ SettingsLabel,
164
+ SettingsInputFrame,
165
+ SettingsSelectFrame,
166
+ } from '@telemetryos/sdk/react'
167
+ import { useCityState, useUnitsState } from '../hooks/store'
168
+
169
+ export default function Settings() {
170
+ const [isLoadingCity, city, setCity] = useCityState()
171
+ const [isLoadingUnits, units, setUnits] = useUnitsState()
172
+
173
+ return (
174
+ <SettingsContainer>
175
+ <SettingsField>
176
+ <SettingsLabel>City</SettingsLabel>
177
+ <SettingsInputFrame>
178
+ <input
179
+ type="text"
180
+ placeholder="Enter city name..."
181
+ disabled={isLoadingCity}
182
+ value={city}
183
+ onChange={(e) => setCity(e.target.value)}
184
+ />
185
+ </SettingsInputFrame>
186
+ </SettingsField>
187
+
188
+ <SettingsField>
189
+ <SettingsLabel>Temperature Units</SettingsLabel>
190
+ <SettingsSelectFrame>
191
+ <select
192
+ disabled={isLoadingUnits}
193
+ value={units}
194
+ onChange={(e) => setUnits(e.target.value as 'imperial' | 'metric')}
195
+ >
196
+ <option value="imperial">Fahrenheit</option>
197
+ <option value="metric">Celsius</option>
198
+ </select>
199
+ </SettingsSelectFrame>
200
+ </SettingsField>
201
+ </SettingsContainer>
202
+ )
203
+ }
204
+ ```
205
+
206
+ ### Render (Weather Display)
207
+
208
+ ```typescript
209
+ // views/Render.tsx
210
+ import { useEffect, useState } from 'react'
211
+ import { weather } from '@telemetryos/sdk'
212
+ import { useCityState, useUnitsState } from '../hooks/store'
213
+
214
+ interface WeatherData {
215
+ temperature: number
216
+ description: string
217
+ humidity: number
218
+ windSpeed: number
219
+ }
220
+
221
+ export default function Render() {
222
+ const [isLoadingCity, city] = useCityState()
223
+ const [isLoadingUnits, units] = useUnitsState()
224
+
225
+ const [data, setData] = useState<WeatherData | null>(null)
226
+ const [loading, setLoading] = useState(false)
227
+ const [error, setError] = useState<string | null>(null)
228
+
229
+ useEffect(() => {
230
+ if (isLoadingCity || isLoadingUnits || !city) return
231
+
232
+ const fetchWeather = async () => {
233
+ setLoading(true)
234
+ setError(null)
235
+
236
+ try {
237
+ const conditions = await weather().getConditions({ city, units })
238
+
239
+ const tempKey = units === 'imperial' ? 'Imperial' : 'Metric'
240
+
241
+ setData({
242
+ temperature: conditions.Temperature[tempKey].Value,
243
+ description: conditions.WeatherText,
244
+ humidity: conditions.RelativeHumidity,
245
+ windSpeed: conditions.Wind.Speed[tempKey].Value,
246
+ })
247
+ } catch (err) {
248
+ setError(err instanceof Error ? err.message : 'Failed to fetch weather')
249
+ } finally {
250
+ setLoading(false)
251
+ }
252
+ }
253
+
254
+ fetchWeather()
255
+
256
+ // Refresh every 10 minutes
257
+ const interval = setInterval(fetchWeather, 10 * 60 * 1000)
258
+ return () => clearInterval(interval)
259
+ }, [city, units, isLoadingCity, isLoadingUnits])
260
+
261
+ // Loading states
262
+ if (isLoadingCity || isLoadingUnits) return <div>Loading config...</div>
263
+ if (!city) return <div>Configure city in Settings</div>
264
+ if (loading && !data) return <div>Loading weather...</div>
265
+ if (error && !data) return <div>Error: {error}</div>
266
+
267
+ const unitSymbol = units === 'imperial' ? '°F' : '°C'
268
+ const speedUnit = units === 'imperial' ? 'mph' : 'km/h'
269
+
270
+ return (
271
+ <div className="weather-display">
272
+ <h1>{city}</h1>
273
+ {data && (
274
+ <>
275
+ <div className="temperature">
276
+ {Math.round(data.temperature)}{unitSymbol}
277
+ </div>
278
+ <div className="description">{data.description}</div>
279
+ <div className="details">
280
+ <span>Humidity: {data.humidity}%</span>
281
+ <span>Wind: {data.windSpeed} {speedUnit}</span>
282
+ </div>
283
+ </>
284
+ )}
285
+ </div>
286
+ )
287
+ }
288
+ ```
289
+
290
+ ## Forecast Example
291
+
292
+ ```typescript
293
+ import { weather } from '@telemetryos/sdk'
294
+
295
+ // Get 5-day forecast
296
+ const forecast = await weather().getDailyForecast({
297
+ city: 'New York',
298
+ units: 'imperial',
299
+ days: 5
300
+ })
301
+
302
+ forecast.forEach(day => {
303
+ console.log(`${day.DateTime}: ${day.Temperature.Value}° - ${day.IconPhrase}`)
304
+ })
305
+ ```
306
+
307
+ ## Weather Icons
308
+
309
+ The API returns `WeatherIcon` as a number (1-44). Map to your icon set:
310
+
311
+ ```typescript
312
+ const iconMap: Record<number, string> = {
313
+ 1: 'sunny',
314
+ 2: 'mostly-sunny',
315
+ 3: 'partly-sunny',
316
+ 4: 'intermittent-clouds',
317
+ 5: 'hazy-sunshine',
318
+ 6: 'mostly-cloudy',
319
+ 7: 'cloudy',
320
+ 8: 'dreary',
321
+ 11: 'fog',
322
+ 12: 'showers',
323
+ 13: 'mostly-cloudy-showers',
324
+ 14: 'partly-sunny-showers',
325
+ 15: 'thunderstorms',
326
+ 16: 'mostly-cloudy-thunderstorms',
327
+ 17: 'partly-sunny-thunderstorms',
328
+ 18: 'rain',
329
+ 19: 'flurries',
330
+ 20: 'mostly-cloudy-flurries',
331
+ 21: 'partly-sunny-flurries',
332
+ 22: 'snow',
333
+ 23: 'mostly-cloudy-snow',
334
+ 24: 'ice',
335
+ 25: 'sleet',
336
+ 26: 'freezing-rain',
337
+ 29: 'rain-and-snow',
338
+ 30: 'hot',
339
+ 31: 'cold',
340
+ 32: 'windy',
341
+ 33: 'clear-night',
342
+ 34: 'mostly-clear-night',
343
+ 35: 'partly-cloudy-night',
344
+ 36: 'intermittent-clouds-night',
345
+ 37: 'hazy-moonlight',
346
+ 38: 'mostly-cloudy-night',
347
+ 39: 'partly-cloudy-showers-night',
348
+ 40: 'mostly-cloudy-showers-night',
349
+ 41: 'partly-cloudy-thunderstorms-night',
350
+ 42: 'mostly-cloudy-thunderstorms-night',
351
+ 43: 'mostly-cloudy-flurries-night',
352
+ 44: 'mostly-cloudy-snow-night',
353
+ }
354
+
355
+ function getIconName(iconNumber: number): string {
356
+ return iconMap[iconNumber] || 'unknown'
357
+ }
358
+ ```
359
+
360
+ ## Error Handling
361
+
362
+ ```typescript
363
+ try {
364
+ const conditions = await weather().getConditions({ city, units })
365
+ } catch (err) {
366
+ if (err instanceof Error) {
367
+ if (err.message.includes('timeout')) {
368
+ // Request timed out (30 second limit)
369
+ } else if (err.message.includes('not found')) {
370
+ // City not found
371
+ } else {
372
+ // Other error
373
+ }
374
+ }
375
+ }
376
+ ```
377
+
378
+ ## Tips
379
+
380
+ 1. **Cache results** - Weather doesn't change rapidly; refresh every 10-30 minutes
381
+ 2. **Handle loading** - Show skeleton or spinner while fetching
382
+ 3. **Show stale data** - Display last known data while refreshing
383
+ 4. **Validate city** - Weather API may fail for invalid city names
384
+ 5. **Use coordinates** - More reliable than city names for precise locations
@@ -5,7 +5,7 @@
5
5
  align-items: center;
6
6
  justify-content: space-between;
7
7
  gap: 2rem;
8
- padding: 5vmin;
8
+ padding: 3rem;
9
9
  color: hsl(210 40% 88%);
10
10
  background: hsl(212 28% 10%);
11
11
  overflow: hidden;
@@ -4,7 +4,7 @@ import { useSubtitleStoreState, useUiScaleStoreState } from '../hooks/store'
4
4
  import './Render.css'
5
5
 
6
6
  export function Render() {
7
- const [_isUiScaleLoading, uiScale] = useUiScaleStoreState()
7
+ const [, uiScale] = useUiScaleStoreState()
8
8
  useUiScaleToSetRem(uiScale)
9
9
  const [isLoading, subtitle] = useSubtitleStoreState()
10
10
 
@@ -9,8 +9,8 @@ import {
9
9
  import { useSubtitleStoreState, useUiScaleStoreState } from '../hooks/store'
10
10
 
11
11
  export function Settings() {
12
- const [isLoadingUiScale, uiScale, setUiScale] = useUiScaleStoreState(0)
13
- const [isLoading, subtitle, setSubtitle] = useSubtitleStoreState()
12
+ const [isLoadingUiScale, uiScale, setUiScale] = useUiScaleStoreState(5)
13
+ const [isLoading, subtitle, setSubtitle] = useSubtitleStoreState(250)
14
14
 
15
15
  return (
16
16
  <SettingsContainer>
@@ -1,7 +0,0 @@
1
- # Agent Guidelines
2
-
3
- This document outlines guidelines for interacting with and developing for AI agents within this project.
4
-
5
- ## Important Notes
6
-
7
- * **Claude-specific Guidelines:** If you are working with Claude models, please refer to `CLAUDE.md` for specific guidelines and best practices.