@telemetryos/cli 1.9.0 → 1.11.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.
- package/CHANGELOG.md +25 -0
- package/dist/commands/auth.js +8 -15
- package/dist/commands/init.js +131 -68
- package/dist/commands/publish.d.ts +22 -0
- package/dist/commands/publish.js +238 -0
- package/dist/index.js +2 -0
- package/dist/plugins/math-tools.d.ts +2 -0
- package/dist/plugins/math-tools.js +18 -0
- package/dist/services/api-client.d.ts +18 -0
- package/dist/services/api-client.js +70 -0
- package/dist/services/archiver.d.ts +4 -0
- package/dist/services/archiver.js +65 -0
- package/dist/services/build-poller.d.ts +10 -0
- package/dist/services/build-poller.js +63 -0
- package/dist/services/cli-config.d.ts +10 -0
- package/dist/services/cli-config.js +45 -0
- package/dist/services/generate-application.d.ts +2 -1
- package/dist/services/generate-application.js +31 -32
- package/dist/services/project-config.d.ts +24 -0
- package/dist/services/project-config.js +51 -0
- package/dist/services/run-server.js +29 -73
- package/dist/types/api.d.ts +44 -0
- package/dist/types/api.js +1 -0
- package/dist/types/applications.d.ts +44 -0
- package/dist/types/applications.js +1 -0
- package/dist/utils/ansi.d.ts +10 -0
- package/dist/utils/ansi.js +10 -0
- package/dist/utils/path-utils.d.ts +55 -0
- package/dist/utils/path-utils.js +99 -0
- package/package.json +4 -2
- package/templates/vite-react-typescript/CLAUDE.md +14 -6
- package/templates/vite-react-typescript/_claude/skills/tos-architecture/SKILL.md +4 -28
- package/templates/vite-react-typescript/_claude/skills/tos-multi-mode/SKILL.md +359 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-design/SKILL.md +304 -12
- package/templates/vite-react-typescript/_claude/skills/tos-render-kiosk-design/SKILL.md +384 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-signage-design/SKILL.md +515 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-ui-design/SKILL.md +325 -0
- package/templates/vite-react-typescript/_claude/skills/tos-requirements/SKILL.md +405 -125
- package/templates/vite-react-typescript/_claude/skills/tos-store-sync/SKILL.md +96 -5
- package/templates/vite-react-typescript/_claude/skills/tos-weather-api/SKILL.md +443 -269
- package/templates/vite-react-typescript/index.html +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type ApplicationKind = 'git' | 'github' | 'uploaded' | null;
|
|
2
|
+
export type Application = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
kind: ApplicationKind;
|
|
7
|
+
baseImage: string;
|
|
8
|
+
buildWorkingPath?: string;
|
|
9
|
+
buildScript?: string;
|
|
10
|
+
buildOutputPath?: string;
|
|
11
|
+
buildEnvironmentVariables?: Record<string, string>;
|
|
12
|
+
versions?: ApplicationVersion[];
|
|
13
|
+
createdAt?: string;
|
|
14
|
+
updatedAt?: string;
|
|
15
|
+
};
|
|
16
|
+
export type ApplicationVersion = {
|
|
17
|
+
name?: string;
|
|
18
|
+
version?: string;
|
|
19
|
+
applicationId: string;
|
|
20
|
+
buildId: string;
|
|
21
|
+
applicationSpecifier: string;
|
|
22
|
+
publishedAt: string;
|
|
23
|
+
};
|
|
24
|
+
export type ApplicationBuild = {
|
|
25
|
+
id: string;
|
|
26
|
+
applicationId: string;
|
|
27
|
+
index: number;
|
|
28
|
+
state: 'pending' | 'building' | 'success' | 'failure' | 'failed' | 'cancelled';
|
|
29
|
+
logs: string[];
|
|
30
|
+
scheduledAt?: string;
|
|
31
|
+
startedAt?: string;
|
|
32
|
+
finishedAt?: string;
|
|
33
|
+
};
|
|
34
|
+
export type CreateApplicationRequest = {
|
|
35
|
+
kind: 'uploaded';
|
|
36
|
+
title: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
baseImage: string;
|
|
39
|
+
baseImageRegistryAuth: string;
|
|
40
|
+
buildWorkingPath: string;
|
|
41
|
+
buildScript: string;
|
|
42
|
+
buildOutputPath: string;
|
|
43
|
+
buildEnvironmentVariables?: Record<string, string>;
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type ApplicationKind = 'git' | 'github' | 'uploaded' | null;
|
|
2
|
+
export type Application = {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
kind: ApplicationKind;
|
|
7
|
+
baseImage: string;
|
|
8
|
+
buildWorkingPath?: string;
|
|
9
|
+
buildScript?: string;
|
|
10
|
+
buildOutputPath?: string;
|
|
11
|
+
buildEnvironmentVariables?: Record<string, string>;
|
|
12
|
+
versions?: ApplicationVersion[];
|
|
13
|
+
createdAt?: string;
|
|
14
|
+
updatedAt?: string;
|
|
15
|
+
};
|
|
16
|
+
export type ApplicationVersion = {
|
|
17
|
+
name?: string;
|
|
18
|
+
version?: string;
|
|
19
|
+
applicationId: string;
|
|
20
|
+
buildId: string;
|
|
21
|
+
applicationSpecifier: string;
|
|
22
|
+
publishedAt: string;
|
|
23
|
+
};
|
|
24
|
+
export type ApplicationBuild = {
|
|
25
|
+
id: string;
|
|
26
|
+
applicationId: string;
|
|
27
|
+
index: number;
|
|
28
|
+
state: 'pending' | 'building' | 'success' | 'failure' | 'failed' | 'cancelled';
|
|
29
|
+
logs: string[];
|
|
30
|
+
scheduledAt?: string;
|
|
31
|
+
startedAt?: string;
|
|
32
|
+
finishedAt?: string;
|
|
33
|
+
};
|
|
34
|
+
export type CreateApplicationRequest = {
|
|
35
|
+
kind: 'uploaded';
|
|
36
|
+
title: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
baseImage: string;
|
|
39
|
+
baseImageRegistryAuth: string;
|
|
40
|
+
buildWorkingPath: string;
|
|
41
|
+
buildScript: string;
|
|
42
|
+
buildOutputPath: string;
|
|
43
|
+
buildEnvironmentVariables?: Record<string, string>;
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const ansi: {
|
|
2
|
+
readonly white: "\u001B[37m";
|
|
3
|
+
readonly yellow: "\u001B[33m";
|
|
4
|
+
readonly green: "\u001B[32m";
|
|
5
|
+
readonly cyan: "\u001B[36m";
|
|
6
|
+
readonly red: "\u001B[31m";
|
|
7
|
+
readonly bold: "\u001B[1m";
|
|
8
|
+
readonly dim: "\u001B[2m";
|
|
9
|
+
readonly reset: "\u001B[0m";
|
|
10
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a string to kebab-case
|
|
3
|
+
*
|
|
4
|
+
* @param str - The string to convert
|
|
5
|
+
* @returns The kebab-cased string
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* toKebabCase('MyApp') // 'my-app'
|
|
9
|
+
* toKebabCase('my_app') // 'my-app'
|
|
10
|
+
* toKebabCase('My App!') // 'my-app'
|
|
11
|
+
* toKebabCase('my--app') // 'my-app'
|
|
12
|
+
*/
|
|
13
|
+
export declare function toKebabCase(str: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Derives a project name from a given path
|
|
16
|
+
*
|
|
17
|
+
* @param projectPath - The path to derive the name from
|
|
18
|
+
* @param currentWorkingDirectory - The current working directory (defaults to process.cwd())
|
|
19
|
+
* @returns The derived project name in kebab-case
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* deriveProjectName('my-project') // 'my-project'
|
|
23
|
+
* deriveProjectName('apps/MyApp') // 'my-app'
|
|
24
|
+
* deriveProjectName('./', '/Users/test/MyProject') // 'my-project'
|
|
25
|
+
* deriveProjectName('../parent') // 'parent'
|
|
26
|
+
* deriveProjectName('/absolute/path/to/app') // 'app'
|
|
27
|
+
*/
|
|
28
|
+
export declare function deriveProjectName(projectPath: string, currentWorkingDirectory?: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Resolves a project path and derives the name
|
|
31
|
+
*
|
|
32
|
+
* @param projectPath - The path to resolve
|
|
33
|
+
* @param currentWorkingDirectory - The current working directory (defaults to process.cwd())
|
|
34
|
+
* @returns An object containing the resolved path and derived name
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* resolveProjectPathAndName('apps/MyApp')
|
|
38
|
+
* // { resolvedPath: '/Users/user/cwd/apps/MyApp', derivedName: 'my-app' }
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveProjectPathAndName(projectPath: string, currentWorkingDirectory?: string): {
|
|
41
|
+
resolvedPath: string;
|
|
42
|
+
derivedName: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Validates a project name according to npm package name requirements
|
|
46
|
+
*
|
|
47
|
+
* @param name - The project name to validate
|
|
48
|
+
* @returns true if valid, or an error message string if invalid
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* validateProjectName('my-app') // true
|
|
52
|
+
* validateProjectName('') // 'Project name cannot be empty'
|
|
53
|
+
* validateProjectName('MyApp') // 'Project name must contain only lowercase letters, numbers, and hyphens'
|
|
54
|
+
*/
|
|
55
|
+
export declare function validateProjectName(name: string): true | string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for path handling and project name derivation
|
|
3
|
+
*/
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* Converts a string to kebab-case
|
|
7
|
+
*
|
|
8
|
+
* @param str - The string to convert
|
|
9
|
+
* @returns The kebab-cased string
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* toKebabCase('MyApp') // 'my-app'
|
|
13
|
+
* toKebabCase('my_app') // 'my-app'
|
|
14
|
+
* toKebabCase('My App!') // 'my-app'
|
|
15
|
+
* toKebabCase('my--app') // 'my-app'
|
|
16
|
+
*/
|
|
17
|
+
export function toKebabCase(str) {
|
|
18
|
+
return (str
|
|
19
|
+
.trim()
|
|
20
|
+
// Remove special characters except spaces, underscores, and hyphens
|
|
21
|
+
.replace(/[^a-zA-Z0-9\s_-]/g, '')
|
|
22
|
+
// Replace spaces and underscores with hyphens
|
|
23
|
+
.replace(/[\s_]+/g, '-')
|
|
24
|
+
// Insert hyphen before uppercase letters preceded by lowercase
|
|
25
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
26
|
+
// Convert to lowercase
|
|
27
|
+
.toLowerCase()
|
|
28
|
+
// Replace multiple consecutive hyphens with single hyphen
|
|
29
|
+
.replace(/-+/g, '-')
|
|
30
|
+
// Remove leading/trailing hyphens
|
|
31
|
+
.replace(/^-+|-+$/g, ''));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Derives a project name from a given path
|
|
35
|
+
*
|
|
36
|
+
* @param projectPath - The path to derive the name from
|
|
37
|
+
* @param currentWorkingDirectory - The current working directory (defaults to process.cwd())
|
|
38
|
+
* @returns The derived project name in kebab-case
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* deriveProjectName('my-project') // 'my-project'
|
|
42
|
+
* deriveProjectName('apps/MyApp') // 'my-app'
|
|
43
|
+
* deriveProjectName('./', '/Users/test/MyProject') // 'my-project'
|
|
44
|
+
* deriveProjectName('../parent') // 'parent'
|
|
45
|
+
* deriveProjectName('/absolute/path/to/app') // 'app'
|
|
46
|
+
*/
|
|
47
|
+
export function deriveProjectName(projectPath, currentWorkingDirectory = process.cwd()) {
|
|
48
|
+
// Resolve the path to handle relative paths
|
|
49
|
+
const resolvedPath = path.resolve(currentWorkingDirectory, projectPath);
|
|
50
|
+
// Get the last segment of the path
|
|
51
|
+
const basename = path.basename(resolvedPath);
|
|
52
|
+
// Convert to kebab-case
|
|
53
|
+
return toKebabCase(basename);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolves a project path and derives the name
|
|
57
|
+
*
|
|
58
|
+
* @param projectPath - The path to resolve
|
|
59
|
+
* @param currentWorkingDirectory - The current working directory (defaults to process.cwd())
|
|
60
|
+
* @returns An object containing the resolved path and derived name
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* resolveProjectPathAndName('apps/MyApp')
|
|
64
|
+
* // { resolvedPath: '/Users/user/cwd/apps/MyApp', derivedName: 'my-app' }
|
|
65
|
+
*/
|
|
66
|
+
export function resolveProjectPathAndName(projectPath, currentWorkingDirectory = process.cwd()) {
|
|
67
|
+
const resolvedPath = path.resolve(currentWorkingDirectory, projectPath);
|
|
68
|
+
const derivedName = deriveProjectName(projectPath, currentWorkingDirectory);
|
|
69
|
+
return { resolvedPath, derivedName };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validates a project name according to npm package name requirements
|
|
73
|
+
*
|
|
74
|
+
* @param name - The project name to validate
|
|
75
|
+
* @returns true if valid, or an error message string if invalid
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* validateProjectName('my-app') // true
|
|
79
|
+
* validateProjectName('') // 'Project name cannot be empty'
|
|
80
|
+
* validateProjectName('MyApp') // 'Project name must contain only lowercase letters, numbers, and hyphens'
|
|
81
|
+
*/
|
|
82
|
+
export function validateProjectName(name) {
|
|
83
|
+
if (!name || name.length === 0) {
|
|
84
|
+
return 'Project name cannot be empty';
|
|
85
|
+
}
|
|
86
|
+
if (name.length > 214) {
|
|
87
|
+
return 'Project name must be 214 characters or less';
|
|
88
|
+
}
|
|
89
|
+
if (name.startsWith('.') || name.startsWith('_')) {
|
|
90
|
+
return 'Project name cannot start with . or _';
|
|
91
|
+
}
|
|
92
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
93
|
+
return 'Project name must contain only lowercase letters, numbers, and hyphens';
|
|
94
|
+
}
|
|
95
|
+
if (name.startsWith('-') || name.endsWith('-')) {
|
|
96
|
+
return 'Project name cannot start or end with a hyphen';
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telemetryos/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "The official TelemetryOS application CLI package. Use it to build applications that run on the TelemetryOS platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,11 +25,13 @@
|
|
|
25
25
|
"license": "",
|
|
26
26
|
"repository": "github:TelemetryTV/Application-API",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@telemetryos/development-application-host-ui": "^1.
|
|
28
|
+
"@telemetryos/development-application-host-ui": "^1.11.0",
|
|
29
29
|
"@types/serve-handler": "^6.1.4",
|
|
30
30
|
"commander": "^14.0.0",
|
|
31
|
+
"ignore": "^6.0.2",
|
|
31
32
|
"inquirer": "^12.9.6",
|
|
32
33
|
"serve-handler": "^6.1.6",
|
|
34
|
+
"tar": "^7.4.3",
|
|
33
35
|
"zod": "^4.1.12"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
@@ -13,8 +13,11 @@ tos serve # Start dev server (or: npm run dev)
|
|
|
13
13
|
**IMPORTANT:** Always run `npm run build` after making changes to check for TypeScript errors. Do not rely solely on the dev server.
|
|
14
14
|
|
|
15
15
|
**Development Host:** http://localhost:2026
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
Both the render and settings mounts points are visible in the development host.
|
|
17
|
+
The Render mount point is presented in a resizable pane.
|
|
18
|
+
The Settings mount point shows in the right sidebar.
|
|
19
|
+
|
|
20
|
+
**The development host is already running!** The user has already started it and the agent doesn't need to run it
|
|
18
21
|
|
|
19
22
|
## Architecture
|
|
20
23
|
|
|
@@ -99,15 +102,20 @@ const response = await proxy().fetch('https://api.example.com/data')
|
|
|
99
102
|
|
|
100
103
|
**IMPORTANT:** You MUST invoke the relevant skill BEFORE writing code for these tasks:
|
|
101
104
|
|
|
105
|
+
**For Render views:** ALWAYS read `tos-render-ui-design` first, then the appropriate specialized skill.
|
|
106
|
+
|
|
102
107
|
| Task | Required Skill | Why |
|
|
103
108
|
|------|----------------|-----|
|
|
104
|
-
|
|
|
109
|
+
| Starting new project | `tos-requirements` | Gather requirements before coding MUST USE |
|
|
110
|
+
| Building ANY Render view | `tos-render-ui-design` | UI scaling foundation - ALWAYS read first |
|
|
111
|
+
| Building digital signage | `tos-render-signage-design` | Display-only patterns (no interaction) |
|
|
112
|
+
| Building interactive kiosk | `tos-render-kiosk-design` | Touch interaction, idle timeout, navigation |
|
|
105
113
|
| Adding ANY Settings UI | `tos-settings-ui` | SDK components are required - raw HTML won't work |
|
|
106
|
-
| Calling external APIs | `tos-proxy-fetch` | Proxy patterns prevent CORS errors |
|
|
107
114
|
| Adding store keys | `tos-store-sync` | Hook patterns ensure Settings↔Render sync |
|
|
108
|
-
|
|
|
115
|
+
| Building multi-mode apps | `tos-multi-mode` | Entity-scoped data, mode switching, namespace patterns |
|
|
116
|
+
| Calling external APIs | `tos-proxy-fetch` | Proxy patterns prevent CORS errors |
|
|
109
117
|
| Media library access | `tos-media-api` | SDK media methods and types |
|
|
110
|
-
|
|
|
118
|
+
| Weather integration | `tos-weather-api` | API-specific patterns and credentials |
|
|
111
119
|
| Debugging issues | `tos-debugging` | Common errors and fixes |
|
|
112
120
|
|
|
113
121
|
**Never write Render layouts, Settings components, or proxy.fetch code without invoking the skill first.**
|
|
@@ -232,15 +232,11 @@ export function App() {
|
|
|
232
232
|
|
|
233
233
|
### Local Development
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
235
|
+
**Development Host:** http://localhost:2026
|
|
236
|
+
Both the render and settings mounts points are visible in the development host.
|
|
237
|
+
The Render mount point is presented in a resizable pane.
|
|
238
|
+
The Settings mount point shows in the right sidebar.
|
|
239
239
|
|
|
240
|
-
# Access locally:
|
|
241
|
-
# Settings: http://localhost:3000/settings
|
|
242
|
-
# Render: http://localhost:3000/render
|
|
243
|
-
```
|
|
244
240
|
|
|
245
241
|
### Build & Deploy
|
|
246
242
|
|
|
@@ -255,26 +251,6 @@ git add . && git commit -m "Update" && git push
|
|
|
255
251
|
|
|
256
252
|
## Common Patterns
|
|
257
253
|
|
|
258
|
-
### Check Mount Point
|
|
259
|
-
|
|
260
|
-
```typescript
|
|
261
|
-
const isSettings = window.location.pathname === '/settings'
|
|
262
|
-
const isRender = window.location.pathname === '/render'
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Conditional Features
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
// In a shared component
|
|
269
|
-
const isRender = window.location.pathname === '/render'
|
|
270
|
-
|
|
271
|
-
// Only fetch external data in Render
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
if (!isRender) return
|
|
274
|
-
fetchExternalData()
|
|
275
|
-
}, [isRender])
|
|
276
|
-
```
|
|
277
|
-
|
|
278
254
|
### Handle Missing Config
|
|
279
255
|
|
|
280
256
|
```typescript
|