skillflow-ai 0.1.0 → 0.3.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 +7 -0
- package/bin/skillflow.mjs +63 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,11 @@ npx skillflow-ai add <slug> --agent codex # into ~/.codex/skills
|
|
|
25
25
|
npx skillflow-ai add <slug> --project # into ./.claude/skills of this folder
|
|
26
26
|
npx skillflow-ai add <slug> --dir <folder> # any folder (Antigravity and others)
|
|
27
27
|
npx skillflow-ai update # update everything you installed
|
|
28
|
+
npx skillflow-ai themes # colour themes for the result
|
|
29
|
+
npx skillflow-ai add <slug> --theme hijau-daun # result in that theme (THEME.md in the skill)
|
|
30
|
+
npx skillflow-ai add <slug> --colors "#1F5E3B,#F2B33D" # or your own two colours
|
|
31
|
+
npx skillflow-ai add <slug> --antislop=core,ui,copywriting # Anti Slop rules in the skill (antislop/)
|
|
32
|
+
npx skillflow-ai antislop # the Anti Slop parts
|
|
28
33
|
npx skillflow-ai remove <slug>
|
|
29
34
|
npx skillflow-ai whoami
|
|
30
35
|
npx skillflow-ai logout
|
|
@@ -32,4 +37,6 @@ npx skillflow-ai logout
|
|
|
32
37
|
|
|
33
38
|
If you have a brand profile on the directory, every skill you add carries it as `BRAND.md`.
|
|
34
39
|
|
|
40
|
+
`--antislop` adds the [Anti Slop](https://github.com/miqdadbadjuber/anti-slop) rules (MIT) as an `antislop/` folder the skill reads before it starts. The core is always included; parts: `ui`, `copywriting`, `human`, `mobile`, `code`. `update` keeps the choice; `--antislop=off` removes it.
|
|
41
|
+
|
|
35
42
|
The token stops working when your account leaves Pro, or when you revoke it on the directory.
|
package/bin/skillflow.mjs
CHANGED
|
@@ -36,7 +36,7 @@ function parse(argv) {
|
|
|
36
36
|
if (a.startsWith('--')) {
|
|
37
37
|
const [k, v] = a.slice(2).split('=')
|
|
38
38
|
if (v !== undefined) opts[k] = v
|
|
39
|
-
else if (argv[i + 1] && !argv[i + 1].startsWith('-') && ['agent', 'dir', 'server', 'kind', 'token'].includes(k)) opts[k] = argv[++i]
|
|
39
|
+
else if (argv[i + 1] && !argv[i + 1].startsWith('-') && ['agent', 'dir', 'server', 'kind', 'token', 'theme', 'colors', 'antislop'].includes(k)) opts[k] = argv[++i]
|
|
40
40
|
else opts[k] = true
|
|
41
41
|
} else if (a === '-h') opts.help = true
|
|
42
42
|
else args.push(a)
|
|
@@ -76,9 +76,37 @@ function targetDir(opts) {
|
|
|
76
76
|
return AGENTS[agent]
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
// Colour theme of the result, sent as the same `?tema=` the directory's ZIP link uses. undefined = not given,
|
|
80
|
+
// '' = no theme (the skill's own colours; also how --theme default clears a saved one).
|
|
81
|
+
function themeQuery(opts) {
|
|
82
|
+
if (opts.colors && opts.colors !== true) {
|
|
83
|
+
const c = String(opts.colors).split(',').map(s => s.trim())
|
|
84
|
+
if (c.length !== 2 || !c.every(x => /^#?[0-9a-fA-F]{6}$/.test(x))) fail('--colors takes two hex colours: --colors "#1F5E3B,#F2B33D"')
|
|
85
|
+
const hex = c.map(x => (x.startsWith('#') ? x : '#' + x).toUpperCase())
|
|
86
|
+
return `?tema=custom&utama=${encodeURIComponent(hex[0])}&aksen=${encodeURIComponent(hex[1])}`
|
|
87
|
+
}
|
|
88
|
+
if (opts.theme === undefined) return undefined
|
|
89
|
+
if (opts.theme === true) fail('Name a theme: --theme <name> (see: npx skillflow-ai themes)')
|
|
90
|
+
if (['default', 'none'].includes(opts.theme)) return ''
|
|
91
|
+
if (!/^[a-z-]{1,40}$/.test(opts.theme)) fail(`"${opts.theme}" is not a theme name. See: npx skillflow-ai themes`)
|
|
92
|
+
return `?tema=${opts.theme}`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Anti Slop rules (antislop/ folder in the skill), sent as the same `?antislop=` the directory's ZIP link uses.
|
|
96
|
+
// undefined = not given, '' = off (also how --antislop=off clears a saved choice). The core is always part of it.
|
|
97
|
+
function antislopValue(opts) {
|
|
98
|
+
if (opts.antislop === undefined) return undefined
|
|
99
|
+
if (opts.antislop === true) return 'core'
|
|
100
|
+
const v = String(opts.antislop).toLowerCase().replace(/\s+/g, '')
|
|
101
|
+
if (['off', 'none', 'no'].includes(v)) return ''
|
|
102
|
+
if (!/^[a-z]+(,[a-z]+)*$/.test(v)) fail('--antislop takes parts separated by commas: --antislop=core,ui,copywriting (see: npx skillflow-ai antislop)')
|
|
103
|
+
return v
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function install(slug, dir, theme = '', antislop = '') {
|
|
80
107
|
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(slug)) fail(`"${slug}" is not a skill name.`)
|
|
81
|
-
const
|
|
108
|
+
const q = [theme.replace(/^\?/, ''), antislop ? 'antislop=' + encodeURIComponent(antislop) : ''].filter(Boolean).join('&')
|
|
109
|
+
const { buf, version } = await api(`/api/skills/v1/skills/${slug}/bundle${q ? '?' + q : ''}`, { raw: true })
|
|
82
110
|
const entries = readZip(buf)
|
|
83
111
|
// Bundles hold "<slug>/…". Anything outside that folder is ignored.
|
|
84
112
|
const own = entries.filter(e => e.name === slug + '/' || e.name.startsWith(slug + '/'))
|
|
@@ -98,7 +126,7 @@ async function install(slug, dir) {
|
|
|
98
126
|
rmSync(final, { recursive: true, force: true })
|
|
99
127
|
renameSync(tmp, final)
|
|
100
128
|
const list = readJson(INSTALLED, {})
|
|
101
|
-
list[final] = { slug, version: version || null, dir, at: new Date().toISOString() }
|
|
129
|
+
list[final] = { slug, version: version || null, dir, theme: theme || null, antislop: antislop || null, at: new Date().toISOString() }
|
|
102
130
|
writePrivate(INSTALLED, list)
|
|
103
131
|
return { final, version }
|
|
104
132
|
}
|
|
@@ -109,10 +137,16 @@ const HELP = `skillflow ${VERSION}: install SkillFlow skills into your AI agent
|
|
|
109
137
|
npx skillflow-ai whoami who the token belongs to
|
|
110
138
|
npx skillflow-ai list [--kind video] skills you can install
|
|
111
139
|
npx skillflow-ai add <slug> [<slug>…] install into ~/.claude/skills
|
|
140
|
+
--theme <name> | --colors "#hex,#hex" colour theme of the result (THEME.md)
|
|
141
|
+
--antislop=core,ui,copywriting Anti Slop rules in the skill (antislop/)
|
|
112
142
|
--agent codex ~/.codex/skills instead
|
|
113
143
|
--project ./.claude/skills (or ./.codex/skills) in this folder
|
|
114
144
|
--dir <folder> any folder (Antigravity and other agents)
|
|
115
145
|
npx skillflow-ai update [<slug>] update installed skills to the latest version
|
|
146
|
+
--theme <name> | --colors … | --theme default change the colour theme while updating
|
|
147
|
+
--antislop=<parts> | --antislop=off change the Anti Slop rules while updating
|
|
148
|
+
npx skillflow-ai themes list the colour themes
|
|
149
|
+
npx skillflow-ai antislop list the Anti Slop parts
|
|
116
150
|
npx skillflow-ai remove <slug> [--dir <folder>] delete an installed skill
|
|
117
151
|
npx skillflow-ai logout forget the token on this computer
|
|
118
152
|
`
|
|
@@ -153,8 +187,10 @@ async function main() {
|
|
|
153
187
|
case 'add': {
|
|
154
188
|
if (!args.length) fail('Name a skill: npx skillflow-ai add <slug>')
|
|
155
189
|
const dir = targetDir(opts)
|
|
190
|
+
const theme = themeQuery(opts) ?? ''
|
|
191
|
+
const antislop = antislopValue(opts) ?? ''
|
|
156
192
|
for (const slug of args) {
|
|
157
|
-
const r = await install(slug, dir)
|
|
193
|
+
const r = await install(slug, dir, theme, antislop)
|
|
158
194
|
say(`✓ ${slug}${r.version ? ' v' + r.version : ''} → ${r.final}`)
|
|
159
195
|
}
|
|
160
196
|
break
|
|
@@ -165,16 +201,36 @@ async function main() {
|
|
|
165
201
|
if (!want.length) { say('Nothing installed yet.'); break }
|
|
166
202
|
const { skills } = await api('/api/skills/v1/catalog')
|
|
167
203
|
const latest = Object.fromEntries(skills.map(s => [s.slug, s.version]))
|
|
204
|
+
// The theme a skill was installed with is kept; --theme / --colors replaces it (and reinstalls).
|
|
205
|
+
const given = themeQuery(opts)
|
|
206
|
+
const givenAs = antislopValue(opts)
|
|
168
207
|
let n = 0
|
|
169
208
|
for (const [, r] of want) {
|
|
170
209
|
if (!latest[r.slug]) { say(`- ${r.slug}: no longer in the catalog (left as it is)`); continue }
|
|
171
|
-
|
|
172
|
-
const
|
|
210
|
+
const theme = given ?? (r.theme || '')
|
|
211
|
+
const antislop = givenAs ?? (r.antislop || '')
|
|
212
|
+
if (latest[r.slug] === r.version && !opts.force && theme === (r.theme || '') && antislop === (r.antislop || '')) continue
|
|
213
|
+
const res = await install(r.slug, r.dir, theme, antislop)
|
|
173
214
|
say(`✓ ${r.slug} ${r.version || '?'} → ${res.version || latest[r.slug]}`); n++
|
|
174
215
|
}
|
|
175
216
|
say(n ? `${n} skill(s) updated.` : 'Everything is up to date.')
|
|
176
217
|
break
|
|
177
218
|
}
|
|
219
|
+
case 'antislop': {
|
|
220
|
+
const { antislop } = await api('/api/skills/v1/catalog')
|
|
221
|
+
if (!antislop || !antislop.length) { say('This directory has no Anti Slop rules yet (update the server).'); break }
|
|
222
|
+
for (const k of antislop) say(' ' + k)
|
|
223
|
+
say('\nUse with: npx skillflow-ai add <slug> --antislop=core,ui (the core is always included). Rules: https://github.com/miqdadbadjuber/anti-slop (MIT)')
|
|
224
|
+
break
|
|
225
|
+
}
|
|
226
|
+
case 'themes': {
|
|
227
|
+
const { themes } = await api('/api/skills/v1/catalog')
|
|
228
|
+
if (!themes || !themes.length) { say('This directory has no colour themes yet.'); break }
|
|
229
|
+
for (const t of themes) say(' ' + t)
|
|
230
|
+
say('\nUse one with: npx skillflow-ai add <slug> --theme ' + themes[0])
|
|
231
|
+
say('Or your own two colours: --colors "#1F5E3B,#F2B33D". Without either, the skill keeps its own colours.')
|
|
232
|
+
break
|
|
233
|
+
}
|
|
178
234
|
case 'remove': {
|
|
179
235
|
if (!args.length) fail('Name a skill: npx skillflow-ai remove <slug>')
|
|
180
236
|
const list = readJson(INSTALLED, {})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillflow-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Install SkillFlow AI skills into Claude Code, Codex or any agent folder with one command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "skillflow-ai": "bin/skillflow.mjs", "skillflow": "bin/skillflow.mjs" },
|