@remixmate/cli 0.9.63 → 0.9.64
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/dist/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"version": "0.9.64",
|
|
4
|
+
"generatedAt": "2026-10-04T11:52:39.175Z",
|
|
5
5
|
"skills": [
|
|
6
6
|
{
|
|
7
7
|
"id": "doc-parse",
|
|
@@ -994,7 +994,7 @@
|
|
|
994
994
|
},
|
|
995
995
|
"json_output": {
|
|
996
996
|
"type": "boolean",
|
|
997
|
-
"description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries, or full definitions when template_id / full is set — or { examples: [...] }.
|
|
997
|
+
"description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries, or full definitions when template_id / full is set — or { examples: [...] }. List summaries carry pageUrl (the template's web detail page — show it to the user as a link) and, when the backend serves samples, showcases { count, pageUrl, items }; the template_id view carries top-level pageUrls / showcases maps."
|
|
998
998
|
},
|
|
999
999
|
"open": {
|
|
1000
1000
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixmate/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.64",
|
|
4
4
|
"description": "AI media generation skills for Claude Code / Codex — 12 skills covering image, video, voice, digital human, web screenshot, web recording, script, template registry, rendering, Jianying export, and video deconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -78,7 +78,7 @@ remixmate template-registry --list-templates
|
|
|
78
78
|
|
|
79
79
|
### Show templates to the user
|
|
80
80
|
|
|
81
|
-
When the user asks to see / browse / pick templates, they decide by *watching* samples, not by reading definitions. The list adds, per template,
|
|
81
|
+
When the user asks to see / browse / pick templates, they decide by *watching* samples, not by reading definitions. The list adds, per template, a link to its web detail page (playable samples, layouts, a copy-ready prompt) and the number of samples whenever the backend serves them — table: `↳ detail: <url>` and `↳ samples: N`; JSON: each summary's `pageUrl` and `showcases.count`; `--template-id`: top-level `pageUrls`.
|
|
82
82
|
|
|
83
83
|
- Present each template as: name, aspect ratios, sample count, and its `pageUrl` as a clickable Markdown link. Keep the URL exactly as printed.
|
|
84
84
|
- When the user wants to see what one template looks like, give its link, or run `remixmate template-registry --open <templateId>` (prints the URL; opens the browser only from an interactive terminal — relay the printed URL either way).
|
|
@@ -111,7 +111,7 @@ print(json.dumps(binding, ensure_ascii=False, indent=2))
|
|
|
111
111
|
| `--filter-aspect` | Keep only templates declaring this aspect ratio (e.g. `9:16`). | none |
|
|
112
112
|
| `--filter-language` | Keep only templates whose `contentLanguage` includes this code (`zh`/`en`); language-agnostic templates always show. | none |
|
|
113
113
|
| `--include-beta` | Also show `status: beta` templates (same effect as `ENABLE_BETA_TEMPLATES=1`). | off |
|
|
114
|
-
| `--json-output` | List mode: emit `{ "templates": [...] }` summaries (or full definitions with `--full`) instead of the table. Detail mode (`--template-id`) is always compact JSON. Summaries carry `showcases: { count, pageUrl, items }
|
|
114
|
+
| `--json-output` | List mode: emit `{ "templates": [...] }` summaries (or full definitions with `--full`) instead of the table. Detail mode (`--template-id`) is always compact JSON. Summaries carry `pageUrl` (web detail page) and `showcases: { count, pageUrl, items }`; detail mode carries top-level `pageUrls` and `showcases` maps. Each is absent when the backend does not serve it. | off |
|
|
115
115
|
| `--open <id>` | Print the template's web detail page URL (samples, layouts) and open the browser when run from an interactive terminal. Exits 1 when the backend has no link for it. Cannot be combined with `--template-id`. | — |
|
|
116
116
|
|
|
117
117
|
### List vs. detail
|
|
@@ -72,9 +72,10 @@ Flags:
|
|
|
72
72
|
(samples, layouts); also opens the browser
|
|
73
73
|
when stdout is an interactive terminal
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
Links & samples: list and detail views add each template's web detail-page
|
|
76
|
+
link (registry document-level ``pageUrls``, falling back to the samples
|
|
77
|
+
endpoint) and sample count (showcase_loader.py) when ab-api serves them; when
|
|
78
|
+
it does not, the views are unchanged apart from one stderr warning.
|
|
78
79
|
"""
|
|
79
80
|
|
|
80
81
|
from __future__ import annotations
|
|
@@ -94,6 +95,7 @@ from registry_loader import ( # noqa: E402
|
|
|
94
95
|
RegistryUnreachableError,
|
|
95
96
|
get_template,
|
|
96
97
|
list_templates as load_visible_templates,
|
|
98
|
+
registry_page_urls,
|
|
97
99
|
)
|
|
98
100
|
from showcase_loader import load_showcases, summarize_group # noqa: E402
|
|
99
101
|
|
|
@@ -198,6 +200,23 @@ def _open_in_browser(url: str) -> None:
|
|
|
198
200
|
pass
|
|
199
201
|
|
|
200
202
|
|
|
203
|
+
def _page_url(template_id: object, page_urls: dict[str, str], groups: dict | None) -> str | None:
|
|
204
|
+
"""Web detail page link for one template.
|
|
205
|
+
|
|
206
|
+
The registry's document-level ``pageUrls`` comes first: it rides on the call
|
|
207
|
+
every list makes anyway, so the link survives the samples endpoint being
|
|
208
|
+
down. The samples group's ``pageUrl`` is the fallback (same URL, built by
|
|
209
|
+
the same backend helper).
|
|
210
|
+
"""
|
|
211
|
+
if not isinstance(template_id, str):
|
|
212
|
+
return None
|
|
213
|
+
if page_urls.get(template_id):
|
|
214
|
+
return page_urls[template_id]
|
|
215
|
+
group = (groups or {}).get(template_id)
|
|
216
|
+
url = group.get("pageUrl") if isinstance(group, dict) else None
|
|
217
|
+
return url if isinstance(url, str) and url else None
|
|
218
|
+
|
|
219
|
+
|
|
201
220
|
def _report_unknown_ids(missing: list[str], templates: list[dict]) -> None:
|
|
202
221
|
for tid in missing:
|
|
203
222
|
# Distinguish "gated out by status" from "does not exist" —
|
|
@@ -459,6 +478,7 @@ def main() -> None:
|
|
|
459
478
|
sys.exit(1)
|
|
460
479
|
|
|
461
480
|
by_id = {t.get("templateId"): t for t in templates}
|
|
481
|
+
page_urls = registry_page_urls()
|
|
462
482
|
|
|
463
483
|
# ----- open mode (--open) -------------------------------------------------
|
|
464
484
|
#
|
|
@@ -468,8 +488,9 @@ def main() -> None:
|
|
|
468
488
|
if args.open_id not in by_id:
|
|
469
489
|
_report_unknown_ids([args.open_id], templates)
|
|
470
490
|
sys.exit(1)
|
|
471
|
-
|
|
472
|
-
|
|
491
|
+
page_url = _page_url(args.open_id, page_urls, None)
|
|
492
|
+
if not page_url:
|
|
493
|
+
page_url = _page_url(args.open_id, {}, load_showcases([args.open_id], 1))
|
|
473
494
|
if not page_url:
|
|
474
495
|
print(
|
|
475
496
|
"❌ No web detail page link for this template: the backend does not "
|
|
@@ -520,9 +541,16 @@ def main() -> None:
|
|
|
520
541
|
# chars), which alone pushed the plain call past the tool-result cap and
|
|
521
542
|
# got it spilled to a file the agent cannot read. Humans can `| jq`.
|
|
522
543
|
detail: dict = {"templates": picked}
|
|
523
|
-
# Samples sit beside the definitions, never inside them: the
|
|
524
|
-
# is the template's authoring contract,
|
|
544
|
+
# Samples and links sit beside the definitions, never inside them: the
|
|
545
|
+
# definition is the template's authoring contract, these are web content.
|
|
525
546
|
groups = load_showcases([str(t.get("templateId")) for t in picked], _DETAIL_SHOWCASES)
|
|
547
|
+
links = {
|
|
548
|
+
str(t.get("templateId")): url
|
|
549
|
+
for t in picked
|
|
550
|
+
if (url := _page_url(t.get("templateId"), page_urls, groups))
|
|
551
|
+
}
|
|
552
|
+
if links:
|
|
553
|
+
detail["pageUrls"] = links
|
|
526
554
|
if groups is not None:
|
|
527
555
|
detail["showcases"] = {
|
|
528
556
|
tid: summarize_group(g, _DETAIL_SHOWCASES) for tid, g in groups.items()
|
|
@@ -554,6 +582,8 @@ def main() -> None:
|
|
|
554
582
|
summaries = []
|
|
555
583
|
for t in visible:
|
|
556
584
|
s = _summarize(t)
|
|
585
|
+
if url := _page_url(t.get("templateId"), page_urls, groups):
|
|
586
|
+
s["pageUrl"] = url
|
|
557
587
|
# Absent (not null) when the endpoint is unavailable, so a consumer
|
|
558
588
|
# never mistakes "unknown" for "zero samples".
|
|
559
589
|
if groups is not None and t.get("templateId") in groups:
|
|
@@ -576,6 +606,7 @@ def main() -> None:
|
|
|
576
606
|
return
|
|
577
607
|
|
|
578
608
|
groups = load_showcases([str(t.get("templateId")) for t in visible], _LIST_SHOWCASES)
|
|
609
|
+
any_link = False
|
|
579
610
|
|
|
580
611
|
header = (
|
|
581
612
|
f"\n{'Template ID':<22} {'Name':<18} {'Aspect':<12} "
|
|
@@ -596,12 +627,14 @@ def main() -> None:
|
|
|
596
627
|
hint = _truncate(tpl.get("llmHint"), _SUMMARY_HINT_CHARS)
|
|
597
628
|
if hint:
|
|
598
629
|
print(f"{' ' * 22} ↳ {hint}")
|
|
630
|
+
# Two lines, link on its own: an agent summarizing the table keeps a
|
|
631
|
+
# labelled `detail:` line, a URL trailing a count reads as an aside.
|
|
599
632
|
group = (groups or {}).get(tpl.get("templateId"))
|
|
600
633
|
if group is not None:
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
634
|
+
print(f"{' ' * 22} ↳ samples: {int(group.get('showcaseCount') or 0)}")
|
|
635
|
+
if url := _page_url(tpl.get("templateId"), page_urls, groups):
|
|
636
|
+
print(f"{' ' * 22} ↳ detail: {url}")
|
|
637
|
+
any_link = True
|
|
605
638
|
|
|
606
639
|
print(f"\n{len(visible)} template(s) shown")
|
|
607
640
|
first_id = str(visible[0].get("templateId", "<templateId>"))
|
|
@@ -609,8 +642,8 @@ def main() -> None:
|
|
|
609
642
|
f"Full definition of one template: --template-id {first_id} --json-output "
|
|
610
643
|
"(llmHint / customPayloadSchema / slideSchemas / slotMapping / variants)",
|
|
611
644
|
)
|
|
612
|
-
if
|
|
613
|
-
print(f"Watch samples in the browser: --open {first_id}")
|
|
645
|
+
if any_link:
|
|
646
|
+
print(f"Watch samples / layouts in the browser: open a detail link, or --open {first_id}")
|
|
614
647
|
|
|
615
648
|
|
|
616
649
|
if __name__ == "__main__":
|
|
@@ -306,6 +306,23 @@ def load_registry_data(
|
|
|
306
306
|
return _load_from_url(url, ttl=ttl_seconds, timeout=http_timeout)
|
|
307
307
|
|
|
308
308
|
|
|
309
|
+
def registry_page_urls() -> dict[str, str]:
|
|
310
|
+
"""Document-level ``pageUrls`` (templateId → web detail page), built by ab-api.
|
|
311
|
+
|
|
312
|
+
Kept beside ``templates`` rather than inside each definition: a definition is
|
|
313
|
+
the template's authoring contract, a link is site information. Absent on
|
|
314
|
+
older backends, offline registries, or when the backend has no site address
|
|
315
|
+
configured — returns ``{}`` then (never raises: it is display-only).
|
|
316
|
+
"""
|
|
317
|
+
try:
|
|
318
|
+
raw = load_registry_data().get("pageUrls")
|
|
319
|
+
except Exception: # noqa: BLE001 — the caller already loaded the registry once
|
|
320
|
+
return {}
|
|
321
|
+
if not isinstance(raw, dict):
|
|
322
|
+
return {}
|
|
323
|
+
return {k: v for k, v in raw.items() if isinstance(k, str) and isinstance(v, str) and v}
|
|
324
|
+
|
|
325
|
+
|
|
309
326
|
# ════════════════════════════════════════════════════════════════════════════
|
|
310
327
|
# Indexed views — O(1) template-id lookup + status / beta gating
|
|
311
328
|
#
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"filter_aspect": { "type": "string", "description": "Show only templates that declare this aspect ratio. E.g. '9:16' / '16:9' / '1:1'." },
|
|
20
20
|
"filter_language": { "type": "string", "description": "Show only templates whose contentLanguage includes this code ('zh' or 'en'). Templates with no declared language are always shown (treated as language-agnostic)." },
|
|
21
21
|
"include_beta": { "type": "boolean", "description": "Also list templates with status='beta'. Default off (only 'stable' shows). The ENABLE_BETA_TEMPLATES env var has the same effect process-wide." },
|
|
22
|
-
"json_output": { "type": "boolean", "description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries, or full definitions when template_id / full is set — or { examples: [...] }.
|
|
22
|
+
"json_output": { "type": "boolean", "description": "Emit a JSON result instead of the human-readable table: { templates: [...] } — summaries, or full definitions when template_id / full is set — or { examples: [...] }. List summaries carry pageUrl (the template's web detail page — show it to the user as a link) and, when the backend serves samples, showcases { count, pageUrl, items }; the template_id view carries top-level pageUrls / showcases maps." },
|
|
23
23
|
"open": { "type": "string", "description": "Print the web detail page URL of <templateId> (playable samples, layouts, copy-ready prompt) and open it in the browser when run from an interactive terminal. Relay the printed URL to the user." }
|
|
24
24
|
},
|
|
25
25
|
"required": []
|