@meistrari/tela-skills 1.0.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/README.md +80 -0
- package/cli.ts +103 -0
- package/package.json +25 -0
- package/skill/SKILL.md +168 -0
- package/skill/canvas.ts +391 -0
- package/skill/common.ts +48 -0
- package/skill/create-canvas.md +169 -0
- package/skill/create-project.md +75 -0
- package/skill/index.ts +37 -0
- package/skill/list-projects.md +46 -0
- package/skill/list-prompts.md +70 -0
- package/skill/preload.ts +7 -0
- package/skill/projects.ts +38 -0
- package/skill/prompts.ts +62 -0
- package/skill/setup-session.md +43 -0
- package/skill/update-canvas.md +179 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @meistrari/tela-skills
|
|
2
|
+
|
|
3
|
+
Tela API skills for [Claude Code](https://claude.ai/claude-code). Enables Claude to interact with Tela canvas/prompts directly.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bunx @meistrari/tela-skills
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The installer will:
|
|
12
|
+
- Copy skill files to `~/.claude/skills/tela/`
|
|
13
|
+
- Optionally set up your Tela API key
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Once installed, Claude Code can use the Tela skills via bun preload:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "console.log(await tela.listProjects())"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Available Functions
|
|
24
|
+
|
|
25
|
+
### Projects
|
|
26
|
+
- `tela.listProjects()` - List projects in workspace
|
|
27
|
+
- `tela.createProject({ title })` - Create a new project
|
|
28
|
+
|
|
29
|
+
### Canvas (Prompts)
|
|
30
|
+
- `tela.listPrompts(options?)` - List canvas/prompts
|
|
31
|
+
- `tela.getPrompt(promptId)` - Get a prompt by ID
|
|
32
|
+
- `tela.createCanvas(payload)` - Create a new canvas
|
|
33
|
+
- `tela.getCanvas(canvasId)` - Get canvas + latest version
|
|
34
|
+
- `tela.updateCanvas(canvasId, payload)` - Update canvas (merges config by default)
|
|
35
|
+
|
|
36
|
+
### Helpers
|
|
37
|
+
- `tela.createStructuredOutput(properties)` - Create structured output schema
|
|
38
|
+
- `tela.createVariable(name, type, options?)` - Create a variable definition
|
|
39
|
+
- `tela.createMessage(role, content, index)` - Create a message with proper formatting
|
|
40
|
+
- `tela.markdownToHtml(markdown)` - Convert markdown to Tela HTML format
|
|
41
|
+
|
|
42
|
+
## Authentication
|
|
43
|
+
|
|
44
|
+
The API key is stored at `~/.tela/session`. You can set it up during installation or manually:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
mkdir -p ~/.tela && echo "YOUR_API_KEY" > ~/.tela/session
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Example: Create Canvas with Structured Output
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const canvas = await tela.createCanvas({
|
|
54
|
+
title: 'My Canvas',
|
|
55
|
+
projectId: 'PROJECT_ID',
|
|
56
|
+
workspaceId: 'WORKSPACE_ID',
|
|
57
|
+
version: {
|
|
58
|
+
title: 'v1',
|
|
59
|
+
configuration: {
|
|
60
|
+
model: 'gpt-5',
|
|
61
|
+
type: 'chat',
|
|
62
|
+
temperature: 0,
|
|
63
|
+
structuredOutput: tela.createStructuredOutput({
|
|
64
|
+
summary: { type: 'string', description: 'Brief summary' },
|
|
65
|
+
keyPoints: { type: 'array', items: { type: 'string' } }
|
|
66
|
+
})
|
|
67
|
+
},
|
|
68
|
+
messages: [
|
|
69
|
+
tela.createMessage('system', '## Task\n\nAnalyze the document.', 0)
|
|
70
|
+
],
|
|
71
|
+
variables: [
|
|
72
|
+
tela.createVariable('document', 'file', { allowMultimodal: true })
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/cli.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import * as p from '@clack/prompts'
|
|
3
|
+
import { existsSync, mkdirSync, cpSync, writeFileSync, readdirSync } from 'fs'
|
|
4
|
+
import { homedir } from 'os'
|
|
5
|
+
import { join, dirname } from 'path'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
const SKILLS_DIR = join(homedir(), '.claude', 'skills', 'tela')
|
|
10
|
+
const SESSION_DIR = join(homedir(), '.tela')
|
|
11
|
+
const SESSION_PATH = join(SESSION_DIR, 'session')
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
p.intro('Tela Skills for Claude Code')
|
|
15
|
+
|
|
16
|
+
const skillsExist = existsSync(SKILLS_DIR)
|
|
17
|
+
|
|
18
|
+
if (skillsExist) {
|
|
19
|
+
const update = await p.confirm({
|
|
20
|
+
message: 'Tela skills already installed. Update to latest version?',
|
|
21
|
+
initialValue: true,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (p.isCancel(update) || !update) {
|
|
25
|
+
p.cancel('Installation cancelled.')
|
|
26
|
+
process.exit(0)
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
const install = await p.confirm({
|
|
30
|
+
message: 'Install Tela skills to ~/.claude/skills/tela/?',
|
|
31
|
+
initialValue: true,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
if (p.isCancel(install) || !install) {
|
|
35
|
+
p.cancel('Installation cancelled.')
|
|
36
|
+
process.exit(0)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const spinner = p.spinner()
|
|
41
|
+
spinner.start('Installing skill files...')
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
mkdirSync(SKILLS_DIR, { recursive: true })
|
|
45
|
+
|
|
46
|
+
const sourceDir = join(__dirname, 'skill')
|
|
47
|
+
const files = readdirSync(sourceDir)
|
|
48
|
+
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
cpSync(join(sourceDir, file), join(SKILLS_DIR, file))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
spinner.stop(`Installed ${files.length} files to ${SKILLS_DIR}`)
|
|
54
|
+
} catch (error) {
|
|
55
|
+
spinner.stop('Installation failed')
|
|
56
|
+
p.log.error(String(error))
|
|
57
|
+
process.exit(1)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const sessionExists = existsSync(SESSION_PATH)
|
|
61
|
+
|
|
62
|
+
if (!sessionExists) {
|
|
63
|
+
const setupKey = await p.confirm({
|
|
64
|
+
message: 'Set up Tela API key now?',
|
|
65
|
+
initialValue: true,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
if (!p.isCancel(setupKey) && setupKey) {
|
|
69
|
+
const apiKey = await p.text({
|
|
70
|
+
message: 'Enter your Tela API key:',
|
|
71
|
+
placeholder: 'tela_...',
|
|
72
|
+
validate: (value) => {
|
|
73
|
+
if (!value) return 'API key is required'
|
|
74
|
+
if (value.length < 10) return 'API key seems too short'
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
if (!p.isCancel(apiKey) && apiKey) {
|
|
79
|
+
mkdirSync(SESSION_DIR, { recursive: true })
|
|
80
|
+
writeFileSync(SESSION_PATH, apiKey, { mode: 0o600 })
|
|
81
|
+
p.log.success('API key saved to ~/.tela/session')
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
p.log.info('You can set up your API key later by running:')
|
|
85
|
+
p.log.message('mkdir -p ~/.tela && echo "YOUR_KEY" > ~/.tela/session')
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
p.log.info('API key already configured at ~/.tela/session')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
p.note(
|
|
92
|
+
`Use in Claude Code with bun --preload:
|
|
93
|
+
|
|
94
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "
|
|
95
|
+
console.log(await tela.listProjects())
|
|
96
|
+
"`,
|
|
97
|
+
'Usage'
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
p.outro('Tela skills installed successfully!')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
main().catch(console.error)
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meistrari/tela-skills",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Tela API skills for Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tela-skills": "./cli.ts"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"cli.ts",
|
|
11
|
+
"skill/**/*"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"tela",
|
|
15
|
+
"claude",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"skills",
|
|
18
|
+
"ai"
|
|
19
|
+
],
|
|
20
|
+
"author": "Meistrari",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^0.9.1"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tela
|
|
3
|
+
description: Skills for interacting with Tela - view, create, and update prompts/canvas. Use this skill when user shares a Tela URL (app.tela.com) or asks about canvas/prompts. Do NOT use WebFetch for Tela URLs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tela API Skills
|
|
7
|
+
|
|
8
|
+
Skills for interacting with the Tela API. Note: Prompts are called "Canvas" in Tela.
|
|
9
|
+
|
|
10
|
+
**IMPORTANT**: When the user shares a Tela URL like `https://app.tela.com/prompt/{id}/craft`, use these skills to fetch and modify the canvas - do NOT use WebFetch.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bunx @meistrari/tela-skills
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Authentication
|
|
19
|
+
|
|
20
|
+
The API uses Bearer token authentication. The token is stored at `~/.tela/session`.
|
|
21
|
+
|
|
22
|
+
## Using These Skills
|
|
23
|
+
|
|
24
|
+
Use `bun` with `--preload` to make the `tela` object globally available:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "console.log(await tela.listProjects())"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Available Functions
|
|
31
|
+
|
|
32
|
+
### Projects & Prompts
|
|
33
|
+
|
|
34
|
+
- `tela.listProjects()` - List all projects in the workspace
|
|
35
|
+
- `tela.createProject({ title })` - Create a new project
|
|
36
|
+
- `tela.listPrompts(options?)` - List prompts/canvas with optional filtering
|
|
37
|
+
- `tela.getPrompt(promptId)` - Get a single prompt by ID
|
|
38
|
+
- `tela.getPromotedVersion(promptId)` - Get the promoted version of a prompt
|
|
39
|
+
|
|
40
|
+
### Canvas Operations
|
|
41
|
+
|
|
42
|
+
- `tela.createCanvas(payload)` - Create a new canvas with optional initial version
|
|
43
|
+
- `tela.getCanvas(canvasId)` - Get canvas + latest version by canvas ID
|
|
44
|
+
- `tela.updateCanvas(canvasId, payload, { merge: true })` - Update canvas (merges config by default)
|
|
45
|
+
- `tela.updateCanvasVersion(versionId, payload)` - Low-level: update by version ID
|
|
46
|
+
- `tela.createCanvasVersion(canvasId, payload)` - Create a new version for existing canvas
|
|
47
|
+
- `tela.getCanvasVersion(versionId)` - Get a canvas version by version ID
|
|
48
|
+
|
|
49
|
+
### Helper Functions
|
|
50
|
+
|
|
51
|
+
- `tela.createStructuredOutput(properties, options?)` - Create structured output schema
|
|
52
|
+
- `tela.createVariable(name, type, options?)` - Create a variable definition
|
|
53
|
+
- `tela.createMessage(role, content, index)` - Create a message with proper HTML/markdown formatting
|
|
54
|
+
- `tela.markdownToHtml(markdown)` - Convert markdown to HTML with variable formatting
|
|
55
|
+
- `tela.getProjectUrl(projectId)` - Get URL to view project in Tela app
|
|
56
|
+
- `tela.getCanvasUrl(canvasId)` - Get URL to view canvas in Tela app
|
|
57
|
+
|
|
58
|
+
## Defaults
|
|
59
|
+
|
|
60
|
+
- **Model**: Always use `gpt-5`
|
|
61
|
+
- **Temperature**: Always use `0`
|
|
62
|
+
- **Prompts**: Use markdown with `## Headings` for readability
|
|
63
|
+
- **Output format**: Use `structuredOutput` config, NEVER put format templates in the prompt text
|
|
64
|
+
|
|
65
|
+
## Quick Examples
|
|
66
|
+
|
|
67
|
+
### List Projects (returns max 10 by default)
|
|
68
|
+
```bash
|
|
69
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "console.log(JSON.stringify(await tela.listProjects(), null, 2))"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Create Canvas with Structured Output
|
|
73
|
+
```bash
|
|
74
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "
|
|
75
|
+
const canvas = await tela.createCanvas({
|
|
76
|
+
title: 'My Canvas',
|
|
77
|
+
projectId: 'PROJECT_ID',
|
|
78
|
+
workspaceId: 'WORKSPACE_ID',
|
|
79
|
+
version: {
|
|
80
|
+
title: 'v1',
|
|
81
|
+
configuration: {
|
|
82
|
+
model: 'gpt-5',
|
|
83
|
+
type: 'chat',
|
|
84
|
+
temperature: 0,
|
|
85
|
+
structuredOutput: tela.createStructuredOutput({
|
|
86
|
+
summary: { type: 'string', description: 'Brief summary' },
|
|
87
|
+
keyPoints: { type: 'array', items: { type: 'string' } }
|
|
88
|
+
})
|
|
89
|
+
},
|
|
90
|
+
messages: [
|
|
91
|
+
tela.createMessage('system', '## Task\n\nAnalyze the document.\n\n## Input\n\n{document}', 0)
|
|
92
|
+
],
|
|
93
|
+
variables: [tela.createVariable('document', 'file', { allowMultimodal: true })]
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
console.log('Created:', canvas.id, tela.getCanvasUrl(canvas.id))
|
|
97
|
+
"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**IMPORTANT**: Define output format in `structuredOutput`, not in the prompt text!
|
|
101
|
+
|
|
102
|
+
### Update Canvas (merges config by default)
|
|
103
|
+
```bash
|
|
104
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "
|
|
105
|
+
const updated = await tela.updateCanvas('CANVAS_ID', {
|
|
106
|
+
configuration: { model: 'gpt-5' },
|
|
107
|
+
variables: [tela.createVariable('input', 'file', { allowMultimodal: true })]
|
|
108
|
+
})
|
|
109
|
+
console.log('Updated:', updated.id)
|
|
110
|
+
"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Get Canvas Info
|
|
114
|
+
```bash
|
|
115
|
+
bun --preload ~/.claude/skills/tela/preload.ts -e "
|
|
116
|
+
const { canvas, version } = await tela.getCanvas('CANVAS_ID')
|
|
117
|
+
console.log('Title:', canvas.title)
|
|
118
|
+
console.log('Model:', version?.configuration?.model)
|
|
119
|
+
console.log('Variables:', version?.variables?.map(v => v.name))
|
|
120
|
+
"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Data Structures
|
|
124
|
+
|
|
125
|
+
### Variables
|
|
126
|
+
```typescript
|
|
127
|
+
{ name: 'input', type: 'text' | 'file' | 'mixed', required: true, description?: 'Description' }
|
|
128
|
+
```
|
|
129
|
+
Referenced in content as `{variableName}` (single braces)
|
|
130
|
+
|
|
131
|
+
### Structured Output
|
|
132
|
+
```typescript
|
|
133
|
+
{
|
|
134
|
+
enabled: true,
|
|
135
|
+
schema: {
|
|
136
|
+
properties: {
|
|
137
|
+
fieldName: { type: 'string', description: 'Field description' }
|
|
138
|
+
},
|
|
139
|
+
title: 'defaultOutput',
|
|
140
|
+
description: 'Schema description',
|
|
141
|
+
type: 'object',
|
|
142
|
+
required: ['fieldName']
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Messages
|
|
148
|
+
```typescript
|
|
149
|
+
{ role: 'system' | 'user' | 'assistant', content: 'Message content', index: 0 }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Environment Variables
|
|
153
|
+
|
|
154
|
+
- `TELA_API_URL` - Override the API base URL (default: `https://api.tela.com`)
|
|
155
|
+
- `TELA_APP_URL` - Override the app base URL (default: `https://app.tela.com`)
|
|
156
|
+
|
|
157
|
+
## File Structure
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
~/.claude/skills/tela/
|
|
161
|
+
├── SKILL.md # This file
|
|
162
|
+
├── preload.ts # Preload script - makes `tela` globally available
|
|
163
|
+
├── index.ts # Barrel export
|
|
164
|
+
├── common.ts # Shared utilities (loadApiKey, apiRequest)
|
|
165
|
+
├── projects.ts # Project functions
|
|
166
|
+
├── prompts.ts # Prompt/Canvas list functions
|
|
167
|
+
└── canvas.ts # Canvas create/update functions
|
|
168
|
+
```
|