@acedatacloud/skills 2026.703.4 → 2026.703.6
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/package.json +1 -1
- package/skills/apple-notes/SKILL.md +10 -2
- package/skills/hashnode/SKILL.md +147 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.703.
|
|
3
|
+
"version": "2026.703.6",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -10,6 +10,7 @@ when_to_use: |
|
|
|
10
10
|
notes, so create / append / move / delete are GATED behind an explicit
|
|
11
11
|
confirmation.
|
|
12
12
|
allowed_tools: [Bash]
|
|
13
|
+
surfaces: [mac]
|
|
13
14
|
license: Apache-2.0
|
|
14
15
|
compatibility: macOS-only. No API token, no connector — Apple Notes has no cloud API. Drives the local Notes.app via AppleScript (osascript); zero external dependencies (Python 3 standard library only). Requires granting Automation access to Notes.app on first run. Does not call api.acedata.cloud.
|
|
15
16
|
metadata:
|
|
@@ -22,8 +23,15 @@ metadata:
|
|
|
22
23
|
Drives the user's **real** Apple Notes through `Notes.app` on macOS. Apple never
|
|
23
24
|
shipped a cloud API for Notes, so there is nothing to OAuth into and no token to
|
|
24
25
|
inject — this skill runs **on the user's own Mac** and talks to Notes.app with
|
|
25
|
-
AppleScript (`osascript`). It works
|
|
26
|
-
|
|
26
|
+
AppleScript (`osascript`). It works wherever an agent runs on macOS: the
|
|
27
|
+
**AceDataCloud desktop app** (which executes local tools / local MCP on the
|
|
28
|
+
user's Mac), Claude Code on macOS, or a CodingBridge node on the user's Mac.
|
|
29
|
+
|
|
30
|
+
> **`surfaces: [mac]`** in the frontmatter marks this skill as **macOS-desktop
|
|
31
|
+
> only** — it cannot run on the web / iOS / Android / Windows surfaces (there is
|
|
32
|
+
> no local `Notes.app` there). The skill/connector directory UI reads this to
|
|
33
|
+
> badge the card ("macOS desktop") and steer users to install it from the macOS
|
|
34
|
+
> desktop app. Absent `surfaces`, a skill is assumed available everywhere.
|
|
27
35
|
|
|
28
36
|
The skill ships [`scripts/notes.py`](scripts/notes.py) — self-contained, Python
|
|
29
37
|
**standard library only** (it shells out to `osascript`; no `pip install`, no
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hashnode
|
|
3
|
+
description: Publish, update and read blog posts on Hashnode via its GraphQL API. Use when the user mentions Hashnode, publishing a blog post to Hashnode, cross-posting an article to their Hashnode blog, saving a Hashnode draft, updating a published Hashnode post, or listing their Hashnode publications and posts.
|
|
4
|
+
when_to_use: |
|
|
5
|
+
Trigger when the user wants to publish a Markdown article to their
|
|
6
|
+
Hashnode blog, save it as a draft, update a previously published
|
|
7
|
+
post, or list / inspect their own Hashnode publications and posts.
|
|
8
|
+
The connector stores a Hashnode Personal Access Token with full
|
|
9
|
+
account access — confirm before publishing publicly (you can save a
|
|
10
|
+
draft first with the createDraft mutation).
|
|
11
|
+
connections: [hashnode]
|
|
12
|
+
allowed_tools: [Bash]
|
|
13
|
+
license: Apache-2.0
|
|
14
|
+
metadata:
|
|
15
|
+
author: acedatacloud
|
|
16
|
+
version: "1.0"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
Call the **Hashnode Public GraphQL API** with `curl + jq`. The user's Personal
|
|
20
|
+
Access Token is in `$HASHNODE_TOKEN`. Single endpoint: `https://gql.hashnode.com`
|
|
21
|
+
(always `POST` a JSON body `{query, variables}`).
|
|
22
|
+
|
|
23
|
+
Every request needs these headers:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Authorization: $HASHNODE_TOKEN # raw token — NO "Bearer " prefix
|
|
27
|
+
Content-Type: application/json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
GraphQL always returns HTTP `200`; real failures live in the JSON `errors`
|
|
31
|
+
array — always inspect it and show it verbatim. An `errors` entry mentioning
|
|
32
|
+
`Unauthorized` / `not authenticated` means the token is invalid → the user must
|
|
33
|
+
re-connect the Hashnode connector.
|
|
34
|
+
|
|
35
|
+
Helper — send a query/mutation (`$1` = query string, `$2` = variables JSON):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
gql() {
|
|
39
|
+
jq -n --arg q "$1" --argjson v "${2:-null}" '{query:$q, variables:$v}' \
|
|
40
|
+
| curl -sS -X POST https://gql.hashnode.com \
|
|
41
|
+
-H "Authorization: $HASHNODE_TOKEN" \
|
|
42
|
+
-H "Content-Type: application/json" \
|
|
43
|
+
-d @-
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Always start by confirming the token and finding the publication id
|
|
48
|
+
|
|
49
|
+
`publishPost` / `createDraft` need a `publicationId`. Fetch the account and its
|
|
50
|
+
publications first (a user can have several blogs):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
gql 'query { me { id username publications(first: 10) { edges { node { id title url } } } } }' \
|
|
54
|
+
| jq '{me: .data.me.username, publications: [.data.me.publications.edges[].node | {id, title, url}], errors: .errors}'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Pick the target blog's `id` (that is the `publicationId`). If the user has
|
|
58
|
+
exactly one publication, use it; otherwise ask which blog to post to.
|
|
59
|
+
|
|
60
|
+
## Publish a post
|
|
61
|
+
|
|
62
|
+
**Confirm with the user before publishing publicly.** If they are not sure, save
|
|
63
|
+
a draft first (see below). `tags` is required — supply 1–5 tags, each as
|
|
64
|
+
`{name, slug}` (slug lowercase, no spaces).
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
PUB_ID="PUBLICATION_ID" # from the me query above
|
|
68
|
+
TITLE="My title"
|
|
69
|
+
BODY_MD="$(cat article.md)" # full Markdown body
|
|
70
|
+
|
|
71
|
+
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
|
|
72
|
+
input: {
|
|
73
|
+
publicationId: $p,
|
|
74
|
+
title: $t,
|
|
75
|
+
contentMarkdown: $b,
|
|
76
|
+
tags: [{name:"AI", slug:"ai"}, {name:"Web Development", slug:"web-development"}]
|
|
77
|
+
}
|
|
78
|
+
}')
|
|
79
|
+
|
|
80
|
+
gql 'mutation PublishPost($input: PublishPostInput!) {
|
|
81
|
+
publishPost(input: $input) { post { id slug url title } }
|
|
82
|
+
}' "$VARS" | jq '{post: .data.publishPost.post, errors: .errors}'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Useful optional `input` fields:
|
|
86
|
+
|
|
87
|
+
- `subtitle` — post subtitle.
|
|
88
|
+
- `slug` — custom URL slug (otherwise derived from the title).
|
|
89
|
+
- `canonicalUrl` / `originalArticleURL` — when cross-posting, point SEO back to
|
|
90
|
+
the original source. Set this whenever the same article also lives elsewhere.
|
|
91
|
+
- `coverImageOptions: { coverImageURL: "https://..." }` — cover image.
|
|
92
|
+
- `publishedAt` — ISO-8601 timestamp to backdate; `disableComments` etc. live
|
|
93
|
+
under `settings`.
|
|
94
|
+
|
|
95
|
+
## Save a draft (safe, non-public)
|
|
96
|
+
|
|
97
|
+
Use this when the user has not explicitly approved public publishing:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
VARS=$(jq -n --arg p "$PUB_ID" --arg t "$TITLE" --arg b "$BODY_MD" '{
|
|
101
|
+
input: { publicationId: $p, title: $t, contentMarkdown: $b }
|
|
102
|
+
}')
|
|
103
|
+
|
|
104
|
+
gql 'mutation CreateDraft($input: CreateDraftInput!) {
|
|
105
|
+
createDraft(input: $input) { draft { id slug title } }
|
|
106
|
+
}' "$VARS" | jq '{draft: .data.createDraft.draft, errors: .errors}'
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Update a published post
|
|
110
|
+
|
|
111
|
+
`updatePost` needs the post `id` (from `publishPost`, or the list query below):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
VARS=$(jq -n --arg id "POST_ID" --arg b "$(cat article.md)" '{
|
|
115
|
+
input: { id: $id, contentMarkdown: $b }
|
|
116
|
+
}')
|
|
117
|
+
|
|
118
|
+
gql 'mutation UpdatePost($input: UpdatePostInput!) {
|
|
119
|
+
updatePost(input: $input) { post { id url title } }
|
|
120
|
+
}' "$VARS" | jq '{post: .data.updatePost.post, errors: .errors}'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## List / inspect my posts
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
gql 'query { me { posts(pageSize: 20, page: 1) { nodes { id title slug url views reactionCount responseCount publishedAt } } } }' \
|
|
127
|
+
| jq '[.data.me.posts.nodes[] | {id, title, url, views, reactions: .reactionCount, responses: .responseCount}]'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Single post with full content + stats:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
gql 'query GetPost($id: ObjectId!) { post(id: $id) { title url views reactionCount responseCount content { markdown } } }' \
|
|
134
|
+
"$(jq -n --arg id "POST_ID" '{id:$id}')" | jq '.data.post | {title, url, views, reactions: .reactionCount}'
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Gotchas
|
|
138
|
+
|
|
139
|
+
- **No `Bearer` prefix** — the `Authorization` header carries the raw token.
|
|
140
|
+
- **`publicationId` is mandatory** for publishing/drafting — never guess it, read
|
|
141
|
+
it from the `me` query.
|
|
142
|
+
- **`tags` is required on `publishPost`** — supply at least one `{name, slug}`;
|
|
143
|
+
slug must be lowercase with hyphens (e.g. `machine-learning`).
|
|
144
|
+
- **`errors` on HTTP 200** — GraphQL reports failures in the `errors` array, not
|
|
145
|
+
via status codes; always surface them.
|
|
146
|
+
- **Idempotency** — re-running `publishPost` creates a *new* post each time; to
|
|
147
|
+
change an existing one use `updatePost` with its `id`.
|