makaron-cli 0.10.0 → 0.11.1
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/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +5 -5
- package/README.md +21 -2
- package/bin/makaron.mjs +278 -5
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +26 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AI image editing, video generation,
|
|
3
|
+
"version": "0.11.1",
|
|
4
|
+
"description": "AI image editing, video generation, music creation, and marketplace skill workflows via CLI. Agents can self-register, install skills, create projects, and produce creative media.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Makaron AI",
|
|
7
7
|
"url": "https://www.makaron.app"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makaron-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AI image editing, video generation,
|
|
3
|
+
"version": "0.11.1",
|
|
4
|
+
"description": "AI image editing, video generation, music creation, and marketplace skill workflows via CLI. Agents can self-register, install skills, create projects, and produce creative media.",
|
|
5
5
|
"displayName": "Makaron",
|
|
6
6
|
"shortDescription": "AI image/video/music creation from the terminal",
|
|
7
|
-
"longDescription": "makaron.app is for humans. makaron-cli is for AI agents. Talk to Makaron Agent from the terminal — create projects
|
|
7
|
+
"longDescription": "makaron.app is for humans. makaron-cli is for AI agents. Talk to Makaron Agent from the terminal — list, search, show, and install marketplace skills; create projects; edit images; generate videos; and compose music. Zero dependencies, single file, works with npx. Agents can self-register to get an API key without human intervention.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Makaron AI",
|
|
10
10
|
"url": "https://www.makaron.app"
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
"homepage": "https://www.makaron.app/agent",
|
|
13
13
|
"repository": "https://github.com/vegekyd/ai-image-editor",
|
|
14
14
|
"license": "MIT",
|
|
15
|
-
"keywords": ["ai", "image-editing", "video", "music", "agent", "creative"],
|
|
15
|
+
"keywords": ["ai", "image-editing", "video", "music", "agent", "creative", "skills"],
|
|
16
16
|
"category": "Creative Tools",
|
|
17
|
-
"capabilities": ["image-editing", "video-generation", "music-creation", "text-to-image"],
|
|
17
|
+
"capabilities": ["image-editing", "video-generation", "music-creation", "text-to-image", "marketplace-skills"],
|
|
18
18
|
"skills": "./skills/",
|
|
19
19
|
"websiteURL": "https://www.makaron.app",
|
|
20
20
|
"brandColor": "#d946ef"
|
package/README.md
CHANGED
|
@@ -7,8 +7,10 @@ Makaron is a multimodal AI creative agent. You talk to it via `makaron chat`, an
|
|
|
7
7
|
## Setup
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# Install makaron-cli globally and add the Makaron Agent Skill.
|
|
11
|
+
npx makaron-cli setup
|
|
12
|
+
|
|
13
|
+
npx makaron-cli --help
|
|
12
14
|
```
|
|
13
15
|
|
|
14
16
|
### Get your API key
|
|
@@ -107,6 +109,23 @@ Returns immediately:
|
|
|
107
109
|
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
108
110
|
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
109
111
|
|
|
112
|
+
### Marketplace skills
|
|
113
|
+
|
|
114
|
+
External users can browse, install, and use marketplace skills with only `MAKARON_API_KEY`:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx makaron-cli skills list
|
|
118
|
+
npx makaron-cli skills search "football"
|
|
119
|
+
npx makaron-cli skills search "足球"
|
|
120
|
+
npx makaron-cli skills show <marketplace-id-or-label>
|
|
121
|
+
npx makaron-cli skills install <marketplace-id-or-label>
|
|
122
|
+
|
|
123
|
+
# chat auto-installs matched marketplace skills before starting the run
|
|
124
|
+
npx makaron-cli chat --project auto --image selfie.jpg --skill <marketplace-id-or-label> -b "make this with the selected skill"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`--skill` accepts an installed skill name, a marketplace UUID, or a unique marketplace label. If a marketplace skill is matched, the CLI installs or reuses it and sends `[Active skill: <installed-skill-name>]` to Makaron Agent. Ordinary users do not need admin commands, and the CLI intentionally does not expose skill deletion.
|
|
128
|
+
|
|
110
129
|
### With additional images (existing project)
|
|
111
130
|
|
|
112
131
|
```bash
|
package/bin/makaron.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import fs from 'fs';
|
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import { createInterface } from 'readline';
|
|
17
17
|
import { execFileSync } from 'child_process';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
18
19
|
|
|
19
20
|
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
20
21
|
|
|
@@ -267,12 +268,13 @@ function printChatHelp() {
|
|
|
267
268
|
console.log(`Makaron chat — create and edit with Makaron Agent
|
|
268
269
|
|
|
269
270
|
Usage:
|
|
270
|
-
makaron chat --project <id|auto> [options] "your message"
|
|
271
|
+
makaron chat --project <id|auto> [options] [--skill <id|label|name>] "your message"
|
|
271
272
|
|
|
272
273
|
Options:
|
|
273
274
|
--project <id|auto> Project to work in. Use "auto" to create one.
|
|
274
275
|
--image <file|url> Attach a reference image or screenshot. Repeatable.
|
|
275
276
|
--video <file|url> Attach a video to the project timeline. Repeatable.
|
|
277
|
+
--skill <id|label|name> Use an installed skill or auto-install a matched marketplace skill.
|
|
276
278
|
--model <name> Preferred image/model route.
|
|
277
279
|
--video-model <name> Preferred video model: seedance-fast, seedance, kling, or grok.
|
|
278
280
|
--video-resolution <res> Video resolution: auto, 480p, 720p, 1080p, or 4k.
|
|
@@ -291,6 +293,9 @@ What you can ask:
|
|
|
291
293
|
Video from image or timeline
|
|
292
294
|
makaron chat --project <id> "make this into a 5 second cinematic video"
|
|
293
295
|
|
|
296
|
+
Marketplace skill
|
|
297
|
+
makaron chat --project auto --image selfie.jpg --skill "Football Captain" "make this cinematic"
|
|
298
|
+
|
|
294
299
|
Fix one video moment from a screenshot
|
|
295
300
|
makaron chat --project <id> --image screenshot.png "@4 this frame should be Paris; only fix this moment"
|
|
296
301
|
|
|
@@ -792,6 +797,155 @@ function timeSince(date) {
|
|
|
792
797
|
return `${Math.floor(s / 86400)}d ago`;
|
|
793
798
|
}
|
|
794
799
|
|
|
800
|
+
// ─── Skill Marketplace ──────────────────────────────────────────────────────
|
|
801
|
+
|
|
802
|
+
function getSkillLabel(skill) {
|
|
803
|
+
return skill.labels?.en || skill.labels?.zh || skill.label || skill.name || skill.id;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function slugifySkill(value) {
|
|
807
|
+
return String(value || '')
|
|
808
|
+
.toLowerCase()
|
|
809
|
+
.normalize('NFKD')
|
|
810
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
811
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
812
|
+
.replace(/^-+|-+$/g, '');
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function normalizeMarketplaceSkill(skill) {
|
|
816
|
+
return {
|
|
817
|
+
...skill,
|
|
818
|
+
label: getSkillLabel(skill),
|
|
819
|
+
skillPath: skill.skillPath || skill.skill_path || null,
|
|
820
|
+
hasSkill: Boolean(skill.skillPath || skill.skill_path),
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async function fetchMarketplaceSkills(baseUrl, opts = {}) {
|
|
825
|
+
let res;
|
|
826
|
+
try {
|
|
827
|
+
res = await fetch(`${baseUrl}/api/home-skills`);
|
|
828
|
+
} catch (err) {
|
|
829
|
+
if (opts.optional) return null;
|
|
830
|
+
process.stderr.write(`Failed to load marketplace skills: ${err.message || err}\n`);
|
|
831
|
+
process.exit(1);
|
|
832
|
+
}
|
|
833
|
+
if (!res.ok) {
|
|
834
|
+
if (opts.optional) return null;
|
|
835
|
+
process.stderr.write(`Error ${res.status}: ${await res.text()}\n`);
|
|
836
|
+
process.exit(1);
|
|
837
|
+
}
|
|
838
|
+
const data = await res.json();
|
|
839
|
+
const skills = Array.isArray(data) ? data : (data.skills || []);
|
|
840
|
+
return skills.map(normalizeMarketplaceSkill);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
function marketplaceSearchText(skill) {
|
|
844
|
+
return [
|
|
845
|
+
skill.id,
|
|
846
|
+
skill.label,
|
|
847
|
+
skill.labels?.en,
|
|
848
|
+
skill.labels?.zh,
|
|
849
|
+
skill.prompt,
|
|
850
|
+
slugifySkill(skill.label),
|
|
851
|
+
slugifySkill(skill.labels?.en),
|
|
852
|
+
slugifySkill(skill.labels?.zh),
|
|
853
|
+
].filter(Boolean).join(' ').toLowerCase();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function marketplaceSkillTokens(skill) {
|
|
857
|
+
return [
|
|
858
|
+
skill.id,
|
|
859
|
+
skill.label,
|
|
860
|
+
skill.labels?.en,
|
|
861
|
+
skill.labels?.zh,
|
|
862
|
+
skill.prompt,
|
|
863
|
+
].filter(Boolean).map(value => String(value).toLowerCase());
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
function findMarketplaceSkill(skills, identifier) {
|
|
867
|
+
const raw = String(identifier || '').trim();
|
|
868
|
+
if (!raw) return null;
|
|
869
|
+
const lower = raw.toLowerCase();
|
|
870
|
+
const slug = slugifySkill(raw);
|
|
871
|
+
const exact = skills.filter(skill => {
|
|
872
|
+
const labels = Object.values(skill.labels || {}).map(v => String(v).toLowerCase());
|
|
873
|
+
const slugMatches = slug
|
|
874
|
+
? slugifySkill(getSkillLabel(skill)) === slug ||
|
|
875
|
+
Object.values(skill.labels || {}).some(v => slugifySkill(v) === slug)
|
|
876
|
+
: false;
|
|
877
|
+
return skill.id === raw ||
|
|
878
|
+
skill.id?.toLowerCase() === lower ||
|
|
879
|
+
getSkillLabel(skill).toLowerCase() === lower ||
|
|
880
|
+
labels.includes(lower) ||
|
|
881
|
+
slugMatches;
|
|
882
|
+
});
|
|
883
|
+
if (exact.length === 1) return exact[0];
|
|
884
|
+
if (exact.length > 1) {
|
|
885
|
+
process.stderr.write(`Multiple marketplace skills match "${raw}". Use an id:\n`);
|
|
886
|
+
exact.forEach(skill => process.stderr.write(` ${skill.id} ${skill.label}\n`));
|
|
887
|
+
process.exit(1);
|
|
888
|
+
}
|
|
889
|
+
const prefix = skills.filter(skill => skill.id?.startsWith(raw));
|
|
890
|
+
if (prefix.length === 1) return prefix[0];
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function printMarketplaceSkills(skills) {
|
|
895
|
+
if (!skills.length) {
|
|
896
|
+
console.log('No marketplace skills found.');
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
console.log(`📦 ${skills.length} marketplace skills\n`);
|
|
900
|
+
for (const skill of skills) {
|
|
901
|
+
const kind = skill.hasSkill ? 'skill' : 'prompt';
|
|
902
|
+
console.log(` ${skill.id} ${skill.label} [${kind}]`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
function printMarketplaceSkill(skill) {
|
|
907
|
+
console.log(`${skill.label}`);
|
|
908
|
+
console.log(`ID: ${skill.id}`);
|
|
909
|
+
console.log(`Type: ${skill.hasSkill ? 'installable skill' : 'prompt template'}`);
|
|
910
|
+
if (skill.labels?.zh && skill.labels.zh !== skill.label) console.log(`ZH: ${skill.labels.zh}`);
|
|
911
|
+
if (skill.prompt) console.log(`Prompt: ${skill.prompt}`);
|
|
912
|
+
if (skill.image) console.log(`Cover: ${skill.image}`);
|
|
913
|
+
if (skill.hasSkill) console.log(`Install: makaron skills install ${skill.id}`);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
async function installMarketplaceSkill(baseUrl, headers, skill, opts = {}) {
|
|
917
|
+
if (!skill.hasSkill) {
|
|
918
|
+
process.stderr.write(`"${skill.label}" is a prompt-only marketplace item and has no installable skill package.\n`);
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
if (!opts.quiet) process.stderr.write(`📦 Installing skill: ${skill.label}\n`);
|
|
922
|
+
const res = await fetch(`${baseUrl}/api/skills`, {
|
|
923
|
+
method: 'POST',
|
|
924
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
925
|
+
body: JSON.stringify({ skillPath: skill.skillPath, homeSkillId: skill.id }),
|
|
926
|
+
});
|
|
927
|
+
const data = await res.json().catch(() => ({}));
|
|
928
|
+
if (!res.ok || !data.success) {
|
|
929
|
+
process.stderr.write(`Install failed: ${data.error || res.status}\n`);
|
|
930
|
+
process.exit(1);
|
|
931
|
+
}
|
|
932
|
+
if (!opts.quiet) {
|
|
933
|
+
const suffix = data.alreadyInstalled ? 'already installed' : 'installed';
|
|
934
|
+
process.stderr.write(`✅ Skill ${suffix}: ${data.skillName}\n`);
|
|
935
|
+
}
|
|
936
|
+
return data;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
async function resolveChatSkill(baseUrl, headers, activeSkill) {
|
|
940
|
+
if (!activeSkill) return undefined;
|
|
941
|
+
const skills = await fetchMarketplaceSkills(baseUrl, { optional: true });
|
|
942
|
+
if (!skills) return activeSkill;
|
|
943
|
+
const marketplaceSkill = findMarketplaceSkill(skills, activeSkill);
|
|
944
|
+
if (!marketplaceSkill) return activeSkill;
|
|
945
|
+
const result = await installMarketplaceSkill(baseUrl, headers, marketplaceSkill);
|
|
946
|
+
return result.skillName;
|
|
947
|
+
}
|
|
948
|
+
|
|
795
949
|
// ─── MCP Tool Caller ─────────────────────────────────────────────────────────
|
|
796
950
|
|
|
797
951
|
async function callMcpTool(baseUrl, headers, toolName, args) {
|
|
@@ -1048,6 +1202,8 @@ function printRootHelp() {
|
|
|
1048
1202
|
console.log(`Makaron CLI — Talk to Makaron Agent from the terminal
|
|
1049
1203
|
|
|
1050
1204
|
Commands:
|
|
1205
|
+
setup Install makaron-cli globally and add the Agent Skill
|
|
1206
|
+
install-skill Install Makaron Agent Skill into your coding agent
|
|
1051
1207
|
register --json Get challenge for agent self-registration
|
|
1052
1208
|
register --verify --challenge-id <id> --answer <n> Verify and save API key
|
|
1053
1209
|
claim Get claim URL for human to link account
|
|
@@ -1059,6 +1215,7 @@ Commands:
|
|
|
1059
1215
|
create --title "name" Create empty project (text-to-image)
|
|
1060
1216
|
|
|
1061
1217
|
chat --project <id> "message" Chat (non-blocking, polls for result)
|
|
1218
|
+
chat --project <id> --skill <id> Use or auto-install a marketplace skill
|
|
1062
1219
|
chat --project <id> --video <file> Attach video to conversation
|
|
1063
1220
|
chat --project <id> -b "message" Background: submit and print runId
|
|
1064
1221
|
chat --project <id> --stream "msg" Legacy: stream SSE in real-time
|
|
@@ -1068,6 +1225,7 @@ Commands:
|
|
|
1068
1225
|
responses get <runId> --wait Poll until completed
|
|
1069
1226
|
responses list --project <id> List runs for a project
|
|
1070
1227
|
abort <runId> Abort a running Agent
|
|
1228
|
+
skills list|search|show|install Browse and install marketplace skills
|
|
1071
1229
|
|
|
1072
1230
|
edit [--image <file>] "prompt" AI image edit / text-to-image
|
|
1073
1231
|
analyze --video <file|url> Analyze video content
|
|
@@ -1082,13 +1240,56 @@ Environment:
|
|
|
1082
1240
|
`);
|
|
1083
1241
|
}
|
|
1084
1242
|
|
|
1243
|
+
function installAgentSkill(values = []) {
|
|
1244
|
+
if (hasHelpFlag(values)) {
|
|
1245
|
+
console.log('Usage: makaron install-skill [--global] [--agent <agent>] [--yes]');
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
const skillDir = fileURLToPath(new URL('../skills/makaron', import.meta.url));
|
|
1250
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
1251
|
+
if (!fs.existsSync(skillFile)) {
|
|
1252
|
+
console.error(`Makaron Agent Skill not found at ${skillFile}`);
|
|
1253
|
+
process.exit(1);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
execFileSync('npx', [
|
|
1257
|
+
'-y',
|
|
1258
|
+
'skills',
|
|
1259
|
+
'add',
|
|
1260
|
+
skillDir,
|
|
1261
|
+
'--skill',
|
|
1262
|
+
'makaron',
|
|
1263
|
+
'--copy',
|
|
1264
|
+
...values,
|
|
1265
|
+
], { stdio: 'inherit' });
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
function setupMakaron(values = []) {
|
|
1269
|
+
if (hasHelpFlag(values)) {
|
|
1270
|
+
console.log('Usage: makaron setup [--agent <agent>]');
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
const version = getCliVersion();
|
|
1275
|
+
console.error(`Installing ${NPM_PACKAGE_NAME}@${version} globally...`);
|
|
1276
|
+
execFileSync('npm', ['install', '-g', `${NPM_PACKAGE_NAME}@${version}`], { stdio: 'inherit' });
|
|
1277
|
+
|
|
1278
|
+
const skillArgs = [...values];
|
|
1279
|
+
if (!skillArgs.includes('--global') && !skillArgs.includes('-g')) skillArgs.unshift('--global');
|
|
1280
|
+
if (!skillArgs.includes('--yes') && !skillArgs.includes('-y')) skillArgs.push('--yes');
|
|
1281
|
+
|
|
1282
|
+
console.error('Installing Makaron Agent Skill globally...');
|
|
1283
|
+
installAgentSkill(skillArgs);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1085
1286
|
function printHelp(topic, subtopic) {
|
|
1086
1287
|
if (topic === 'login') {
|
|
1087
1288
|
console.log('Usage: makaron login');
|
|
1088
1289
|
} else if (topic === 'create') {
|
|
1089
1290
|
console.log('Usage: makaron create --image <file> [--image <file2>] | --image-url <url> | --title "name"');
|
|
1090
1291
|
} else if (topic === 'chat') {
|
|
1091
|
-
|
|
1292
|
+
printChatHelp();
|
|
1092
1293
|
} else if (topic === 'responses' || topic === 'run') {
|
|
1093
1294
|
if (subtopic === 'get') console.log('Usage: makaron responses get <runId> [--wait] [--json] [--pick <field>]');
|
|
1094
1295
|
else if (subtopic === 'watch') console.log('Usage: makaron responses watch <runId> [--jsonl] [--interval <ms>]');
|
|
@@ -1109,6 +1310,24 @@ function printHelp(topic, subtopic) {
|
|
|
1109
1310
|
`);
|
|
1110
1311
|
} else if (topic === 'abort') {
|
|
1111
1312
|
console.log('Usage: makaron abort <runId>');
|
|
1313
|
+
} else if (topic === 'setup') {
|
|
1314
|
+
console.log('Usage: makaron setup [--agent <agent>]');
|
|
1315
|
+
} else if (topic === 'install-skill') {
|
|
1316
|
+
console.log('Usage: makaron install-skill [--global] [--agent <agent>] [--yes]');
|
|
1317
|
+
} else if (topic === 'skills') {
|
|
1318
|
+
if (subtopic === 'list') console.log('Usage: makaron skills list [--json]');
|
|
1319
|
+
else if (subtopic === 'search') console.log('Usage: makaron skills search <query> [--json]');
|
|
1320
|
+
else if (subtopic === 'show') console.log('Usage: makaron skills show <marketplace-id|label> [--json]');
|
|
1321
|
+
else if (subtopic === 'install') console.log('Usage: makaron skills install <marketplace-id|label> [--json]');
|
|
1322
|
+
else console.log(`Skill marketplace commands:
|
|
1323
|
+
skills list List marketplace skills
|
|
1324
|
+
skills search <query> Search marketplace skills
|
|
1325
|
+
skills show <id|label> Show a marketplace skill
|
|
1326
|
+
skills install <id|label> Install a marketplace skill to your workspace
|
|
1327
|
+
|
|
1328
|
+
Use with chat:
|
|
1329
|
+
makaron chat --project auto --skill <id|label> "your request"
|
|
1330
|
+
`);
|
|
1112
1331
|
} else if (topic === 'edit') {
|
|
1113
1332
|
console.log('Usage: makaron edit [--image <file|url>] [--model gemini|qwen|openai] [--skill enhance|creative|wild|captions] [--ref <file>] [--out <file>] "prompt"');
|
|
1114
1333
|
} else if (topic === 'analyze') {
|
|
@@ -1168,6 +1387,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1168
1387
|
printHelp(command, args[1]);
|
|
1169
1388
|
} else if (command === '--version' || command === '-v' || command === 'version') {
|
|
1170
1389
|
console.log(getCliVersion());
|
|
1390
|
+
} else if (command === 'setup') {
|
|
1391
|
+
setupMakaron(args.slice(1));
|
|
1392
|
+
} else if (command === 'install-skill') {
|
|
1393
|
+
installAgentSkill(args.slice(1));
|
|
1171
1394
|
} else if (command === 'login') {
|
|
1172
1395
|
await login();
|
|
1173
1396
|
} else if (command === 'create') {
|
|
@@ -1206,6 +1429,7 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1206
1429
|
else if (args[i] === '--image' && args[i + 1]) chatImages.push(args[++i]);
|
|
1207
1430
|
else if (args[i] === '--video' && args[i + 1]) chatVideos.push(args[++i]);
|
|
1208
1431
|
else if (args[i] === '--skill' && args[i + 1]) activeSkill = args[++i];
|
|
1432
|
+
else if (args[i].startsWith('--skill=')) activeSkill = args[i].slice('--skill='.length);
|
|
1209
1433
|
else if (args[i] === '--stream') useStream = true;
|
|
1210
1434
|
else if (args[i] === '--background' || args[i] === '-b') background = true;
|
|
1211
1435
|
else if (args[i] === '--json') jsonOutput = true;
|
|
@@ -1297,8 +1521,10 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1297
1521
|
}
|
|
1298
1522
|
}
|
|
1299
1523
|
|
|
1524
|
+
const resolvedSkill = await resolveChatSkill(baseUrl, headers, activeSkill);
|
|
1525
|
+
|
|
1300
1526
|
// Upload videos to project timeline (via /api/projects/create with videoUrls)
|
|
1301
|
-
let finalPrompt =
|
|
1527
|
+
let finalPrompt = resolvedSkill ? `[Active skill: ${resolvedSkill}]\n${prompt}` : prompt;
|
|
1302
1528
|
if (chatVideos.length > 0) {
|
|
1303
1529
|
// Upload local files via signed URL (no size limit, works with API key auth)
|
|
1304
1530
|
const uploadedVideoUrls = [...prevalidatedVideoUrlList];
|
|
@@ -1376,10 +1602,9 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1376
1602
|
if (sub === 'get') {
|
|
1377
1603
|
const runId = args[2];
|
|
1378
1604
|
if (!runId) { console.error('Usage: makaron responses get <runId> [--wait] [--json] [--pick <field>]'); process.exit(1); }
|
|
1379
|
-
let wait = false,
|
|
1605
|
+
let wait = false, pick = null;
|
|
1380
1606
|
for (let i = 3; i < args.length; i++) {
|
|
1381
1607
|
if (args[i] === '--wait') wait = true;
|
|
1382
|
-
if (args[i] === '--json') jsonOutput = true;
|
|
1383
1608
|
if (args[i] === '--pick' && args[i + 1]) pick = args[++i];
|
|
1384
1609
|
}
|
|
1385
1610
|
|
|
@@ -1439,6 +1664,54 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
1439
1664
|
} else if (command === 'list' || command === 'ls') {
|
|
1440
1665
|
const { headers, baseUrl } = getAuth();
|
|
1441
1666
|
await listProjects(baseUrl, headers);
|
|
1667
|
+
} else if (command === 'skills') {
|
|
1668
|
+
const sub = args[1] || 'list';
|
|
1669
|
+
const baseUrl = process.env.MAKARON_URL || DEFAULT_URL;
|
|
1670
|
+
const jsonOutput = args.includes('--json');
|
|
1671
|
+
|
|
1672
|
+
if (sub === 'list') {
|
|
1673
|
+
const skills = await fetchMarketplaceSkills(baseUrl);
|
|
1674
|
+
if (jsonOutput) console.log(JSON.stringify({ skills }, null, 2));
|
|
1675
|
+
else printMarketplaceSkills(skills);
|
|
1676
|
+
} else if (sub === 'search') {
|
|
1677
|
+
const query = args.filter((arg, index) => index > 1 && arg !== '--json').join(' ').trim();
|
|
1678
|
+
if (!query) { console.error('Usage: makaron skills search <query> [--json]'); process.exit(1); }
|
|
1679
|
+
const lowerQuery = query.toLowerCase();
|
|
1680
|
+
const slugQuery = slugifySkill(query);
|
|
1681
|
+
const skills = (await fetchMarketplaceSkills(baseUrl))
|
|
1682
|
+
.filter(skill => {
|
|
1683
|
+
const rawMatch = marketplaceSkillTokens(skill).some(token => token.includes(lowerQuery));
|
|
1684
|
+
const slugMatch = slugQuery ? marketplaceSearchText(skill).includes(slugQuery) : false;
|
|
1685
|
+
return rawMatch || slugMatch;
|
|
1686
|
+
});
|
|
1687
|
+
if (jsonOutput) console.log(JSON.stringify({ skills }, null, 2));
|
|
1688
|
+
else printMarketplaceSkills(skills);
|
|
1689
|
+
} else if (sub === 'show') {
|
|
1690
|
+
const identifier = args[2];
|
|
1691
|
+
if (!identifier) { console.error('Usage: makaron skills show <marketplace-id|label> [--json]'); process.exit(1); }
|
|
1692
|
+
const skills = await fetchMarketplaceSkills(baseUrl);
|
|
1693
|
+
const skill = findMarketplaceSkill(skills, identifier);
|
|
1694
|
+
if (!skill) { console.error(`Skill not found: ${identifier}`); process.exit(1); }
|
|
1695
|
+
if (jsonOutput) console.log(JSON.stringify(skill, null, 2));
|
|
1696
|
+
else printMarketplaceSkill(skill);
|
|
1697
|
+
} else if (sub === 'install') {
|
|
1698
|
+
const identifier = args[2];
|
|
1699
|
+
if (!identifier) { console.error('Usage: makaron skills install <marketplace-id|label> [--json]'); process.exit(1); }
|
|
1700
|
+
const { headers, baseUrl: authedBaseUrl } = getAuth();
|
|
1701
|
+
const skills = await fetchMarketplaceSkills(authedBaseUrl);
|
|
1702
|
+
const skill = findMarketplaceSkill(skills, identifier);
|
|
1703
|
+
if (!skill) { console.error(`Skill not found: ${identifier}`); process.exit(1); }
|
|
1704
|
+
const data = await installMarketplaceSkill(authedBaseUrl, headers, skill, { quiet: jsonOutput });
|
|
1705
|
+
if (jsonOutput) console.log(JSON.stringify({ ...data, marketplaceId: skill.id, label: skill.label }, null, 2));
|
|
1706
|
+
else console.log(data.skillName);
|
|
1707
|
+
} else {
|
|
1708
|
+
console.log(`Skill marketplace commands:
|
|
1709
|
+
skills list List marketplace skills
|
|
1710
|
+
skills search <query> Search marketplace skills
|
|
1711
|
+
skills show <id|label> Show a marketplace skill
|
|
1712
|
+
skills install <id|label> Install a marketplace skill to your workspace
|
|
1713
|
+
`);
|
|
1714
|
+
}
|
|
1442
1715
|
} else if (command === 'project' || command === 'projects') {
|
|
1443
1716
|
const { headers, baseUrl } = getAuth();
|
|
1444
1717
|
const sub = args[1];
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -96,6 +96,32 @@ Returns immediately:
|
|
|
96
96
|
| Add music | `npx makaron-cli chat --project <id> "add calm piano background music"` |
|
|
97
97
|
| Create motion design | `npx makaron-cli chat --project <id> "make an animated Instagram story with this image"` |
|
|
98
98
|
|
|
99
|
+
### Marketplace skills
|
|
100
|
+
|
|
101
|
+
Use marketplace skills when the user asks for a named Makaron effect, template, or skill such as "Football Captain", "足球队长", "World Cup MVP", or a marketplace UUID.
|
|
102
|
+
|
|
103
|
+
External users only need `MAKARON_API_KEY`; no admin permissions are required for listing, searching, showing, installing, or using marketplace skills.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Browse public marketplace skills
|
|
107
|
+
npx makaron-cli skills list
|
|
108
|
+
npx makaron-cli skills search "football"
|
|
109
|
+
npx makaron-cli skills search "足球"
|
|
110
|
+
npx makaron-cli skills show <marketplace-id-or-label>
|
|
111
|
+
|
|
112
|
+
# Install a marketplace skill into the API key owner's workspace
|
|
113
|
+
npx makaron-cli skills install <marketplace-id-or-label>
|
|
114
|
+
|
|
115
|
+
# Use a marketplace skill. If the skill is not installed yet, chat auto-installs it,
|
|
116
|
+
# then injects the installed skill name into the agent run.
|
|
117
|
+
npx makaron-cli chat --project auto \
|
|
118
|
+
--image selfie.jpg \
|
|
119
|
+
--skill <marketplace-id-or-label> \
|
|
120
|
+
-b "make this with the selected skill"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`--skill` accepts an installed skill name, a marketplace UUID, or a unique marketplace label. If a marketplace skill is matched, the CLI installs or reuses it and sends `[Active skill: <installed-skill-name>]` to Makaron Agent. Do not call admin skill commands for ordinary users. There is intentionally no user-facing CLI delete command for marketplace skills.
|
|
124
|
+
|
|
99
125
|
### With additional images (existing project)
|
|
100
126
|
|
|
101
127
|
```bash
|