emberflow-skills 1.1.2 → 1.2.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 +31 -13
- package/bin/install.js +15 -10
- package/package.json +5 -3
- package/skills/ember-publish/SKILL.md +2 -0
- package/skills/ember-publish-json/SKILL.md +118 -0
package/README.md
CHANGED
|
@@ -1,46 +1,64 @@
|
|
|
1
1
|
# Emberflow Skills
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Publish beautiful docs from your AI coding tools to [Emberflow](https://www.emberflow.ai) — architecture diagrams, tables, and markdown, hosted instantly.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
The fastest way to get started:
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
npx emberflow-skills
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
That's it. The installer auto-detects your project type (Claude Code or Cursor) and copies the skill to the right directory. You'll be publishing docs in under 10 seconds.
|
|
14
|
+
|
|
15
|
+
### Options
|
|
12
16
|
|
|
13
17
|
```bash
|
|
18
|
+
# Install to current project (default)
|
|
19
|
+
npx emberflow-skills
|
|
20
|
+
|
|
14
21
|
# Install globally for Claude Code (available in all projects)
|
|
15
22
|
npx emberflow-skills --global
|
|
16
23
|
```
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
### What the installer does
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
1. Detects if you're in a Claude Code project (`.claude/`) or Cursor project (`.cursor/`)
|
|
28
|
+
2. Copies the `ember-publish` skill into your project's skills directory
|
|
29
|
+
3. Done — use `/ember-publish` in your next conversation
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
## Usage
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
In Claude Code or Cursor, just type:
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
```
|
|
36
|
+
/ember-publish architecture overview for the payments service
|
|
37
|
+
```
|
|
27
38
|
|
|
28
|
-
|
|
39
|
+
Your AI writes the markdown, generates Mermaid diagrams, and publishes it. You get back a shareable URL.
|
|
29
40
|
|
|
30
|
-
## What
|
|
41
|
+
## What gets published
|
|
31
42
|
|
|
32
43
|
- Live Mermaid diagrams with zoom, pan, and fullscreen
|
|
33
44
|
- Syntax-highlighted code blocks (190+ languages)
|
|
34
45
|
- Auto-generated table of contents
|
|
35
46
|
- Per-block inline comments and discussions
|
|
36
47
|
- Dark mode with font selection
|
|
48
|
+
- Public or private docs with secret links
|
|
37
49
|
|
|
38
|
-
## Manual
|
|
50
|
+
## Manual install
|
|
39
51
|
|
|
40
52
|
If you prefer not to use npx:
|
|
41
53
|
|
|
42
54
|
```bash
|
|
43
|
-
|
|
44
|
-
git clone https://github.com/toptalPatrick/emberflow-skills.git
|
|
55
|
+
git clone https://github.com/pmccurley87/emberflow-skills.git
|
|
45
56
|
cp -r emberflow-skills/skills/ember-publish .claude/skills/
|
|
46
57
|
```
|
|
58
|
+
|
|
59
|
+
## Works with
|
|
60
|
+
|
|
61
|
+
- Claude Code
|
|
62
|
+
- Cursor
|
|
63
|
+
- Codex CLI
|
|
64
|
+
- Any tool that supports the SKILL.md format
|
package/bin/install.js
CHANGED
|
@@ -7,9 +7,9 @@ const http = require('http');
|
|
|
7
7
|
const readline = require('readline');
|
|
8
8
|
const os = require('os');
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const EMBERFLOW_URL = 'https://emberflow.ai';
|
|
10
|
+
const SKILL_NAMES = ['ember-publish', 'ember-publish-json'];
|
|
11
|
+
const SKILLS_DIR = path.join(__dirname, '..', 'skills');
|
|
12
|
+
const EMBERFLOW_URL = 'https://www.emberflow.ai';
|
|
13
13
|
const TOKEN_PATH = path.join(os.homedir(), '.emberflow', 'token.json');
|
|
14
14
|
|
|
15
15
|
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
@@ -80,11 +80,14 @@ function sleep(ms) {
|
|
|
80
80
|
// ── Skill installer ──
|
|
81
81
|
|
|
82
82
|
function install(destDir, label) {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
for (const name of SKILL_NAMES) {
|
|
84
|
+
const src = path.join(SKILLS_DIR, name, 'SKILL.md');
|
|
85
|
+
const skillDir = path.join(destDir, name);
|
|
86
|
+
const destFile = path.join(skillDir, 'SKILL.md');
|
|
87
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
88
|
+
fs.copyFileSync(src, destFile);
|
|
89
|
+
console.log(` ${green('✓')} Installed ${name} to ${path.relative(process.cwd(), skillDir) || skillDir} ${dim(`(${label})`)}`);
|
|
90
|
+
}
|
|
88
91
|
return true;
|
|
89
92
|
}
|
|
90
93
|
|
|
@@ -151,8 +154,10 @@ async function authenticate() {
|
|
|
151
154
|
const status = await request('GET', `${EMBERFLOW_URL}/api/device-code/${code}`);
|
|
152
155
|
|
|
153
156
|
if (status.data.status === 'approved' && status.data.session_token) {
|
|
157
|
+
// Strip cookie name prefix if present (e.g. "__Secure-better-auth.session_token=VALUE" -> "VALUE")
|
|
158
|
+
const raw = status.data.session_token.replace(/^(?:__Secure-)?better-auth\.session_token=/, '');
|
|
154
159
|
fs.mkdirSync(path.dirname(TOKEN_PATH), { recursive: true });
|
|
155
|
-
fs.writeFileSync(TOKEN_PATH, JSON.stringify({ token:
|
|
160
|
+
fs.writeFileSync(TOKEN_PATH, JSON.stringify({ token: raw }, null, 2));
|
|
156
161
|
process.stdout.clearLine(0);
|
|
157
162
|
process.stdout.cursorTo(0);
|
|
158
163
|
console.log(` ${green('✓')} Signed in! Token saved to ${dim('~/.emberflow/token.json')}`);
|
|
@@ -222,7 +227,7 @@ async function main() {
|
|
|
222
227
|
|
|
223
228
|
if (installed > 0) {
|
|
224
229
|
console.log();
|
|
225
|
-
console.log(` Use: ${cyan('/ember-publish')} ${dim('[topic]')}`);
|
|
230
|
+
console.log(` Use: ${cyan('/ember-publish')} ${dim('[topic]')} or ${cyan('/ember-publish-json')} ${dim('[data]')}`);
|
|
226
231
|
}
|
|
227
232
|
}
|
|
228
233
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emberflow-skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Install Emberflow skills for AI coding tools",
|
|
5
5
|
"bin": {
|
|
6
6
|
"emberflow-skills": "./bin/install.js"
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
"mcp",
|
|
14
14
|
"ai",
|
|
15
15
|
"documentation",
|
|
16
|
-
"mermaid"
|
|
16
|
+
"mermaid",
|
|
17
|
+
"json",
|
|
18
|
+
"json-explorer"
|
|
17
19
|
],
|
|
18
20
|
"author": "Patrick",
|
|
19
21
|
"license": "MIT",
|
|
20
22
|
"repository": {
|
|
21
23
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/
|
|
24
|
+
"url": "https://github.com/pmccurley87/emberflow-skills"
|
|
23
25
|
}
|
|
24
26
|
}
|
|
@@ -184,6 +184,8 @@ The response JSON includes the URL. Documents are viewable at:
|
|
|
184
184
|
|
|
185
185
|
To **update** an existing document, publish again with the same slug — the API upserts for the same author.
|
|
186
186
|
|
|
187
|
+
> **JSON documents**: You can also publish JSON data by passing `content_type: "json"` in the API payload. The content should be valid JSON (either raw data or the multi-payload format `{"payloads": [{"label": "...", "data": ...}]}`). Use the `/ember-publish-json` skill for a dedicated JSON publishing workflow.
|
|
188
|
+
|
|
187
189
|
### Other Operations
|
|
188
190
|
|
|
189
191
|
```bash
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ember-publish-json
|
|
3
|
+
description: Publish JSON data to Emberflow as an interactive explorer with expand/collapse, search, and multi-payload tabs
|
|
4
|
+
argument-hint: [JSON file path, API response, or description of data to publish]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Emberflow JSON Publisher
|
|
8
|
+
|
|
9
|
+
Publish JSON data to Emberflow and view it in an interactive explorer at **https://emberflow.ai** with collapsible tree nodes, property search, copy values/paths, and multi-payload tabs.
|
|
10
|
+
|
|
11
|
+
## Step 1: Prepare the JSON
|
|
12
|
+
|
|
13
|
+
Collect the JSON data to publish. This can be:
|
|
14
|
+
- A JSON file on disk
|
|
15
|
+
- An API response
|
|
16
|
+
- Multiple JSON payloads to compare side-by-side
|
|
17
|
+
|
|
18
|
+
### Multi-Payload Format
|
|
19
|
+
|
|
20
|
+
To publish multiple JSON payloads as tabs, wrap them in this format:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"payloads": [
|
|
25
|
+
{ "label": "API Response", "data": { ... } },
|
|
26
|
+
{ "label": "Config", "data": { ... } }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If you publish a single JSON value (object, array, etc.) without the wrapper, the explorer will display it as a single "Data" tab.
|
|
32
|
+
|
|
33
|
+
## Step 2: Authenticate (if needed)
|
|
34
|
+
|
|
35
|
+
Session tokens are stored at `~/.emberflow/token.json`. Check if a valid session exists:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cat ~/.emberflow/token.json 2>/dev/null
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If the file exists, verify the token still works:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
curl -s -H "Authorization: Bearer $(jq -r .token ~/.emberflow/token.json)" \
|
|
45
|
+
https://emberflow.ai/api/docs
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If no session exists, it's expired, or the verify call returns 401, authenticate using the device flow:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
EMBERFLOW_URL="https://emberflow.ai"
|
|
52
|
+
|
|
53
|
+
# Step 1: Request a device code
|
|
54
|
+
RESP=$(curl -s -X POST "$EMBERFLOW_URL/api/device-code")
|
|
55
|
+
CODE=$(echo "$RESP" | jq -r .code)
|
|
56
|
+
URL=$(echo "$RESP" | jq -r .verification_url)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Tell the user to open the URL in their browser to sign in and approve the device. Then poll until approved:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Step 2: Poll until approved (every 3s)
|
|
63
|
+
while true; do
|
|
64
|
+
STATUS=$(curl -s "$EMBERFLOW_URL/api/device-code/$CODE")
|
|
65
|
+
S=$(echo "$STATUS" | jq -r .status)
|
|
66
|
+
if [ "$S" = "approved" ]; then
|
|
67
|
+
TOKEN=$(echo "$STATUS" | jq -r .session_token)
|
|
68
|
+
mkdir -p ~/.emberflow
|
|
69
|
+
echo "{\"token\":\"$TOKEN\"}" > ~/.emberflow/token.json
|
|
70
|
+
break
|
|
71
|
+
fi
|
|
72
|
+
if [ "$S" = "expired" ]; then
|
|
73
|
+
echo "Code expired. Please try again."
|
|
74
|
+
break
|
|
75
|
+
fi
|
|
76
|
+
sleep 3
|
|
77
|
+
done
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Step 3: Publish
|
|
81
|
+
|
|
82
|
+
Generate a slug from a title and publish with `content_type: "json"`:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
EMBERFLOW_URL="https://emberflow.ai"
|
|
86
|
+
TITLE="My JSON Data"
|
|
87
|
+
SLUG=$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//;s/-$//')
|
|
88
|
+
TOKEN=$(jq -r .token ~/.emberflow/token.json)
|
|
89
|
+
|
|
90
|
+
# For a single JSON file:
|
|
91
|
+
JSON_FILE="/path/to/data.json"
|
|
92
|
+
CONTENT=$(cat "$JSON_FILE")
|
|
93
|
+
|
|
94
|
+
# For multiple payloads, wrap them:
|
|
95
|
+
# CONTENT=$(jq -n --argjson a "$(cat file1.json)" --argjson b "$(cat file2.json)" \
|
|
96
|
+
# '{payloads: [{label: "Response", data: $a}, {label: "Config", data: $b}]}')
|
|
97
|
+
|
|
98
|
+
curl -s -X POST "$EMBERFLOW_URL/api/docs" \
|
|
99
|
+
-H 'Content-Type: application/json' \
|
|
100
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
101
|
+
-d "$(jq -n --arg slug "$SLUG" --arg title "$TITLE" --arg content "$CONTENT" \
|
|
102
|
+
'{slug: $slug, title: $title, content: $content, content_type: "json", visibility: "public"}')"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The response JSON includes the URL. Documents are viewable at:
|
|
106
|
+
- `https://emberflow.ai/d/<shortId>/<slug>`
|
|
107
|
+
|
|
108
|
+
To **update** an existing JSON document, publish again with the same slug — the API upserts for the same author.
|
|
109
|
+
|
|
110
|
+
### Other Operations
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# List all your documents
|
|
114
|
+
curl -s -H "Authorization: Bearer $TOKEN" "$EMBERFLOW_URL/api/docs"
|
|
115
|
+
|
|
116
|
+
# Delete a document
|
|
117
|
+
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" "$EMBERFLOW_URL/api/docs/SLUG_HERE"
|
|
118
|
+
```
|