@doubledigit/cli 0.6.0 → 0.7.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 +8 -0
- package/dist/commands/actions.d.ts +2 -0
- package/dist/commands/actions.d.ts.map +1 -1
- package/dist/commands/actions.js +17 -1
- package/dist/commands/remotion-hub-add.d.ts +4 -0
- package/dist/commands/remotion-hub-add.d.ts.map +1 -0
- package/dist/commands/remotion-hub-add.js +125 -0
- package/dist/commands/remotion-hub-init.d.ts.map +1 -1
- package/dist/commands/remotion-hub-init.js +12 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/lib/remotion-hub-init.d.ts +38 -0
- package/dist/lib/remotion-hub-init.d.ts.map +1 -1
- package/dist/lib/remotion-hub-init.js +234 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -125,6 +125,14 @@ Remotion Hub `init` is handled locally by the CLI because it creates files on th
|
|
|
125
125
|
|
|
126
126
|
By default, Remotion Hub `init` creates Remotion's Hello World starter so `remotion studio` opens with a visible composition. Pass `--skip-remotion-create` or `--hub-only` only when adding Remotion Hub files to an existing Remotion project.
|
|
127
127
|
|
|
128
|
+
After init, install Remotion AI coding skills when you want editor or agent guidance for Remotion work:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx skills add remotion-dev/skills
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Pass `--skip-skills` to omit that next-step reminder from CLI output. `--non-interactive` is accepted for automation scripts; the command is already prompt-free.
|
|
135
|
+
|
|
128
136
|
When no `--registry`, `--url`, or `--app-url` is passed, Remotion Hub init writes a registry URL from exported `DD_APP_URL`, `APP_URL`, `NEXT_PUBLIC_APP_URL`, or `BETTER_AUTH_URL`; then the release-configured hosted app URL; then `http://localhost:3111` for local development builds.
|
|
129
137
|
|
|
130
138
|
For HTTP-backed actions, the command resolves the app URL from exported `DD_APP_URL`, `APP_URL`, or `BETTER_AUTH_URL`; then local env-file `DD_APP_URL`; then the release-configured hosted app URL. It prints JSON responses to stdout. It also reads `.env`, `.env.local`, `apps/main-app/.env`, and `apps/main-app/.env.local`; exported shell values take precedence.
|
|
@@ -4,6 +4,8 @@ export declare function getActionPositionals(args: string[]): {
|
|
|
4
4
|
index: number;
|
|
5
5
|
}[];
|
|
6
6
|
export declare function isRemotionHubInitAction(args: string[]): boolean;
|
|
7
|
+
export declare function isRemotionHubAddAction(args: string[]): boolean;
|
|
7
8
|
export declare function buildRemotionHubInitCommandArgs(args: string[]): string[];
|
|
9
|
+
export declare function buildRemotionHubAddCommandArgs(args: string[]): string[];
|
|
8
10
|
export declare function actions(args: string[]): Promise<void>;
|
|
9
11
|
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"AAmCA,wBAAgB,uBAAuB,WAKtC;AAkED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE;WACf,MAAM;WAAS,MAAM;IAuBxD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,WAGrD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAGpD;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,YAI7D;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,YAI5D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC3D"}
|
package/dist/commands/actions.js
CHANGED
|
@@ -5,6 +5,7 @@ import { buildActionRequest, fetchActionRequest, isLocalAppUrl, parseActionsArgs
|
|
|
5
5
|
import { DEFAULT_APP_URL, readEnvFile } from '../lib/onboarding.js';
|
|
6
6
|
import { resolveWorkspacePaths } from '../paths.js';
|
|
7
7
|
import { scanWorkspace } from '../scanner.js';
|
|
8
|
+
import { runRemotionHubAddCommand } from './remotion-hub-add.js';
|
|
8
9
|
import { runRemotionHubInitCommand } from './remotion-hub-init.js';
|
|
9
10
|
const actionValueOptions = new Set([
|
|
10
11
|
'--app-url',
|
|
@@ -49,7 +50,9 @@ Options:
|
|
|
49
50
|
|
|
50
51
|
Examples:
|
|
51
52
|
dd actions remotion-hub
|
|
52
|
-
dd actions remotion-hub init my-video --
|
|
53
|
+
dd actions remotion-hub init my-video --non-interactive
|
|
54
|
+
dd actions remotion-hub init my-video --skip-skills
|
|
55
|
+
dd actions remotion-hub add terminal-scene --dir my-video
|
|
53
56
|
dd actions remotion-hub search-components --query "animated chart" --limit 5
|
|
54
57
|
dd actions remotion-hub get-component --namespace doubledigit --slug motion-strip
|
|
55
58
|
dd actions remotion-hub get-registry-payload --json '{"namespace":"doubledigit","slug":"motion-strip"}'
|
|
@@ -115,16 +118,29 @@ export function isRemotionHubInitAction(args) {
|
|
|
115
118
|
const positionals = getActionPositionals(args);
|
|
116
119
|
return positionals[0]?.value === 'remotion-hub' && positionals[1]?.value === 'init';
|
|
117
120
|
}
|
|
121
|
+
export function isRemotionHubAddAction(args) {
|
|
122
|
+
const positionals = getActionPositionals(args);
|
|
123
|
+
return positionals[0]?.value === 'remotion-hub' && positionals[1]?.value === 'add';
|
|
124
|
+
}
|
|
118
125
|
export function buildRemotionHubInitCommandArgs(args) {
|
|
119
126
|
const positionals = getActionPositionals(args);
|
|
120
127
|
const dropIndexes = new Set([positionals[0]?.index, positionals[1]?.index]);
|
|
121
128
|
return args.filter((_, index) => !dropIndexes.has(index));
|
|
122
129
|
}
|
|
130
|
+
export function buildRemotionHubAddCommandArgs(args) {
|
|
131
|
+
const positionals = getActionPositionals(args);
|
|
132
|
+
const dropIndexes = new Set([positionals[0]?.index, positionals[1]?.index]);
|
|
133
|
+
return args.filter((_, index) => !dropIndexes.has(index));
|
|
134
|
+
}
|
|
123
135
|
export async function actions(args) {
|
|
124
136
|
if (isRemotionHubInitAction(args)) {
|
|
125
137
|
runRemotionHubInitCommand(buildRemotionHubInitCommandArgs(args));
|
|
126
138
|
return;
|
|
127
139
|
}
|
|
140
|
+
if (isRemotionHubAddAction(args)) {
|
|
141
|
+
await runRemotionHubAddCommand(buildRemotionHubAddCommandArgs(args));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
128
144
|
const parsed = parseActionsArgs(args);
|
|
129
145
|
if (parsed.help || !parsed.microApp) {
|
|
130
146
|
console.log(buildHelp());
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type RunRemotionHubAddResult } from '../lib/remotion-hub-init.js';
|
|
2
|
+
export declare function buildRemotionHubAddHelp(): string;
|
|
3
|
+
export declare function runRemotionHubAddCommand(args: string[]): Promise<RunRemotionHubAddResult | undefined>;
|
|
4
|
+
//# sourceMappingURL=remotion-hub-add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotion-hub-add.d.ts","sourceRoot":"","sources":["../../src/commands/remotion-hub-add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AA8E9F,wBAAgB,uBAAuB,WAsBtC;AAkBD,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC,CA2B9C"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { runRemotionHubAdd } from '../lib/remotion-hub-init.js';
|
|
2
|
+
const valueFlags = new Set([
|
|
3
|
+
'app-url',
|
|
4
|
+
'dir',
|
|
5
|
+
'namespace',
|
|
6
|
+
'registry',
|
|
7
|
+
'url',
|
|
8
|
+
]);
|
|
9
|
+
function parseArgs(args) {
|
|
10
|
+
const positional = [];
|
|
11
|
+
const flags = {};
|
|
12
|
+
for (let i = 0; i < args.length; i++) {
|
|
13
|
+
const arg = args[i];
|
|
14
|
+
if (!arg)
|
|
15
|
+
continue;
|
|
16
|
+
if (arg === '-h') {
|
|
17
|
+
flags.h = true;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (!arg.startsWith('--')) {
|
|
21
|
+
positional.push(arg);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const [rawKey, inlineValue] = arg.slice(2).split(/=(.*)/s, 2);
|
|
25
|
+
if (!rawKey)
|
|
26
|
+
continue;
|
|
27
|
+
if (inlineValue !== undefined) {
|
|
28
|
+
flags[rawKey] = inlineValue;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (valueFlags.has(rawKey)) {
|
|
32
|
+
const next = args[i + 1];
|
|
33
|
+
if (!next || next.startsWith('--')) {
|
|
34
|
+
throw new Error(`--${rawKey} requires a value`);
|
|
35
|
+
}
|
|
36
|
+
flags[rawKey] = next;
|
|
37
|
+
i++;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (rawKey === 'force'
|
|
41
|
+
|| rawKey === 'help'
|
|
42
|
+
|| rawKey === 'json'
|
|
43
|
+
|| rawKey === 'no-install'
|
|
44
|
+
|| rawKey === 'skip-install') {
|
|
45
|
+
flags[rawKey] = true;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Unknown option for Remotion Hub add: --${rawKey}`);
|
|
49
|
+
}
|
|
50
|
+
return { positional, flags };
|
|
51
|
+
}
|
|
52
|
+
function stringFlag(flags, ...names) {
|
|
53
|
+
for (const name of names) {
|
|
54
|
+
const value = flags[name];
|
|
55
|
+
if (typeof value === 'string' && value.trim())
|
|
56
|
+
return value.trim();
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function booleanFlag(flags, ...names) {
|
|
61
|
+
return names.some((name) => flags[name] === true);
|
|
62
|
+
}
|
|
63
|
+
export function buildRemotionHubAddHelp() {
|
|
64
|
+
return `
|
|
65
|
+
dd actions remotion-hub add - Install a registry component into a local Remotion Hub project
|
|
66
|
+
|
|
67
|
+
Usage:
|
|
68
|
+
dd actions remotion-hub add <item> [options]
|
|
69
|
+
|
|
70
|
+
Options:
|
|
71
|
+
--dir <path> Project directory
|
|
72
|
+
--registry <url> Double Digit app URL or /api/remotion-hub/r endpoint
|
|
73
|
+
--url, --app-url <url> Alias for --registry
|
|
74
|
+
--namespace <name> Registry namespace when item is not namespace/slug
|
|
75
|
+
--force Overwrite existing generated files
|
|
76
|
+
--skip-install Do not install npm dependencies
|
|
77
|
+
--no-install Alias for --skip-install
|
|
78
|
+
--json Print machine-readable JSON
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
dd actions remotion-hub add terminal-scene
|
|
82
|
+
dd actions remotion-hub add doubledigit/terminal-scene --dir ./my-video
|
|
83
|
+
dd actions remotion-hub add terminal-scene --registry https://double-digit.example --skip-install
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
function printAdd(result) {
|
|
87
|
+
console.log(`Added ${result.name} (${result.type})`);
|
|
88
|
+
for (const file of result.written) {
|
|
89
|
+
console.log(` ${file}`);
|
|
90
|
+
}
|
|
91
|
+
if (result.installedDependencies.length > 0) {
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(`Installed dependencies: ${result.installedDependencies.join(', ')}`);
|
|
94
|
+
}
|
|
95
|
+
if (result.snippet) {
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log('Import and composition snippet:');
|
|
98
|
+
console.log(result.snippet);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export async function runRemotionHubAddCommand(args) {
|
|
102
|
+
const parsed = parseArgs(args);
|
|
103
|
+
const json = booleanFlag(parsed.flags, 'json');
|
|
104
|
+
if (booleanFlag(parsed.flags, 'help', 'h')) {
|
|
105
|
+
console.log(buildRemotionHubAddHelp());
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
if (parsed.positional.length !== 1) {
|
|
109
|
+
throw new Error('Usage: dd actions remotion-hub add <item> [options]');
|
|
110
|
+
}
|
|
111
|
+
const result = await runRemotionHubAdd({
|
|
112
|
+
item: parsed.positional[0] ?? '',
|
|
113
|
+
projectDir: stringFlag(parsed.flags, 'dir'),
|
|
114
|
+
registry: stringFlag(parsed.flags, 'registry', 'url', 'app-url'),
|
|
115
|
+
namespace: stringFlag(parsed.flags, 'namespace'),
|
|
116
|
+
force: booleanFlag(parsed.flags, 'force'),
|
|
117
|
+
skipInstall: booleanFlag(parsed.flags, 'skip-install', 'no-install'),
|
|
118
|
+
quiet: json,
|
|
119
|
+
});
|
|
120
|
+
if (json)
|
|
121
|
+
console.log(JSON.stringify(result, null, 2));
|
|
122
|
+
else
|
|
123
|
+
printAdd(result);
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/commands/remotion-hub-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/commands/remotion-hub-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAgFhG,wBAAgB,wBAAwB,WA4BvC;AAmBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,wBAAwB,GAAG,SAAS,CA2B9F"}
|
|
@@ -41,6 +41,8 @@ function parseArgs(args) {
|
|
|
41
41
|
|| rawKey === 'help'
|
|
42
42
|
|| rawKey === 'hub-only'
|
|
43
43
|
|| rawKey === 'json'
|
|
44
|
+
|| rawKey === 'non-interactive'
|
|
45
|
+
|| rawKey === 'skip-skills'
|
|
44
46
|
|| rawKey === 'skip-remotion-create') {
|
|
45
47
|
flags[rawKey] = true;
|
|
46
48
|
continue;
|
|
@@ -76,12 +78,16 @@ Options:
|
|
|
76
78
|
--namespace <name> Registry namespace (default: doubledigit)
|
|
77
79
|
--skip-remotion-create Only add Remotion Hub files; do not run create-video
|
|
78
80
|
--hub-only Alias for --skip-remotion-create
|
|
81
|
+
--skip-skills Do not print the Remotion AI coding skills next step
|
|
82
|
+
--non-interactive Compatibility flag; init is already prompt-free
|
|
79
83
|
--force Overwrite existing generated files
|
|
80
84
|
--json Print machine-readable JSON
|
|
81
85
|
|
|
82
86
|
Examples:
|
|
83
87
|
dd actions remotion-hub init
|
|
84
88
|
dd actions remotion-hub init my-video
|
|
89
|
+
dd actions remotion-hub init my-video --non-interactive
|
|
90
|
+
dd actions remotion-hub init my-video --skip-skills
|
|
85
91
|
dd actions remotion-hub init my-video --registry https://double-digit.example
|
|
86
92
|
`;
|
|
87
93
|
}
|
|
@@ -95,6 +101,11 @@ function printInit(result) {
|
|
|
95
101
|
}
|
|
96
102
|
console.log('');
|
|
97
103
|
console.log(`Registry: ${result.config.registry}`);
|
|
104
|
+
if (!result.skills.skipped) {
|
|
105
|
+
console.log('');
|
|
106
|
+
console.log('Install Remotion AI coding skills:');
|
|
107
|
+
console.log(` ${result.skills.display}`);
|
|
108
|
+
}
|
|
98
109
|
}
|
|
99
110
|
export function runRemotionHubInitCommand(args) {
|
|
100
111
|
const parsed = parseArgs(args);
|
|
@@ -112,6 +123,7 @@ export function runRemotionHubInitCommand(args) {
|
|
|
112
123
|
namespace: stringFlag(parsed.flags, 'namespace'),
|
|
113
124
|
force: booleanFlag(parsed.flags, 'force'),
|
|
114
125
|
skipRemotionCreate: booleanFlag(parsed.flags, 'skip-remotion-create', 'hub-only'),
|
|
126
|
+
skipSkills: booleanFlag(parsed.flags, 'skip-skills'),
|
|
115
127
|
quiet: json,
|
|
116
128
|
});
|
|
117
129
|
if (json)
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* without importing the full extension-management dependency graph first.
|
|
7
7
|
*/
|
|
8
8
|
declare const command: string, args: string[];
|
|
9
|
-
declare const HELP = "\n@doubledigit/cli \u2014 Manage extensions and local setup\n\nCommands:\n doctor Check local prerequisites and project health\n onboard Prepare local development and start the app\n run Start the local app with automatic DB bootstrap\n dev Start DB + app without migrations or seed data\n db <subcommand> Database helpers (status, migrate, create)\n actions <app> [action] Discover and invoke micro-app actions\n create <name> Scaffold a new micro-app from the template\n init <project-name> Scaffold a new Double Digit project\n add|install <source> Install an extension from GitHub or a marketplace\n sync Regenerate micro-apps.ts from dd-apps.config.json\n enable <name> Enable a micro-app (updates config + runs sync)\n disable <name> Disable a micro-app (updates config + runs sync)\n uninstall|remove <name> Completely remove a micro-app\n list List all discovered micro-apps with enabled/disabled status\n info <name> Show detailed info about an installed extension\n outdated Check for outdated marketplace extensions\n reconcile Detect drift between lock file, marketplace, and local files\n marketplace <sub> Manage marketplace registrations (add/list/update/remove)\n browse [marketplace] Browse available extensions in registered marketplaces\n\nOptions:\n --help, -h Show this help message\n\nExamples:\n dd doctor\n dd onboard --yes\n dd onboard # setup + start the dev server\n dd onboard --no-run # setup only\n dd init my-project # scaffold and bootstrap a fresh project\n dd init my-project --run # scaffold + bootstrap + start\n dd init my-project --skip-install --no-git\n dd run\n dd dev\n dd db status\n dd actions remotion-hub init my-video --
|
|
9
|
+
declare const HELP = "\n@doubledigit/cli \u2014 Manage extensions and local setup\n\nCommands:\n doctor Check local prerequisites and project health\n onboard Prepare local development and start the app\n run Start the local app with automatic DB bootstrap\n dev Start DB + app without migrations or seed data\n db <subcommand> Database helpers (status, migrate, create)\n actions <app> [action] Discover and invoke micro-app actions\n create <name> Scaffold a new micro-app from the template\n init <project-name> Scaffold a new Double Digit project\n add|install <source> Install an extension from GitHub or a marketplace\n sync Regenerate micro-apps.ts from dd-apps.config.json\n enable <name> Enable a micro-app (updates config + runs sync)\n disable <name> Disable a micro-app (updates config + runs sync)\n uninstall|remove <name> Completely remove a micro-app\n list List all discovered micro-apps with enabled/disabled status\n info <name> Show detailed info about an installed extension\n outdated Check for outdated marketplace extensions\n reconcile Detect drift between lock file, marketplace, and local files\n marketplace <sub> Manage marketplace registrations (add/list/update/remove)\n browse [marketplace] Browse available extensions in registered marketplaces\n\nOptions:\n --help, -h Show this help message\n\nExamples:\n dd doctor\n dd onboard --yes\n dd onboard # setup + start the dev server\n dd onboard --no-run # setup only\n dd init my-project # scaffold and bootstrap a fresh project\n dd init my-project --run # scaffold + bootstrap + start\n dd init my-project --skip-install --no-git\n dd run\n dd dev\n dd db status\n dd actions remotion-hub init my-video --non-interactive\n dd actions remotion-hub init my-video --skip-skills\n dd actions remotion-hub search-components --query \"animated chart\"\n dd create invoice-tracker\n dd add gh:owner/repo/extensions/micro-apps/habit-tracker\n dd add habit-tracker@community\n dd info habit-tracker\n dd reconcile\n dd marketplace add digitaldouble/dd-marketplace\n dd browse community\n DD_APPS=tasks,agent-v2 dd sync\n";
|
|
10
10
|
declare function requireArg(value: string | undefined, usage: string): string;
|
|
11
11
|
declare function runAddCommand(rawArgs: string[]): Promise<void>;
|
|
12
12
|
declare function main(): Promise<void>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,QAAA,MAAW,OAAO,UAAK,IAAI,UAAgB,CAAC;AAE5C,QAAA,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,QAAA,MAAW,OAAO,UAAK,IAAI,UAAgB,CAAC;AAE5C,QAAA,MAAM,IAAI,2zEAiDT,CAAC;AAEF,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOpE;AAED,iBAAe,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB7D;AAED,iBAAe,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsInC"}
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,8 @@ Examples:
|
|
|
45
45
|
dd run
|
|
46
46
|
dd dev
|
|
47
47
|
dd db status
|
|
48
|
-
dd actions remotion-hub init my-video --
|
|
48
|
+
dd actions remotion-hub init my-video --non-interactive
|
|
49
|
+
dd actions remotion-hub init my-video --skip-skills
|
|
49
50
|
dd actions remotion-hub search-components --query "animated chart"
|
|
50
51
|
dd create invoice-tracker
|
|
51
52
|
dd add gh:owner/repo/extensions/micro-apps/habit-tracker
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
type RemotionSkillsCommand = {
|
|
3
|
+
command: 'npx';
|
|
4
|
+
args: ['skills', 'add', 'remotion-dev/skills'];
|
|
5
|
+
display: 'npx skills add remotion-dev/skills';
|
|
6
|
+
};
|
|
2
7
|
export interface RemotionHubConfig {
|
|
3
8
|
$schema: string;
|
|
4
9
|
registry: string;
|
|
@@ -40,6 +45,7 @@ export interface RunRemotionHubInitOptions {
|
|
|
40
45
|
namespace?: string;
|
|
41
46
|
force?: boolean;
|
|
42
47
|
skipRemotionCreate?: boolean;
|
|
48
|
+
skipSkills?: boolean;
|
|
43
49
|
quiet?: boolean;
|
|
44
50
|
spawnImpl?: typeof spawnSync;
|
|
45
51
|
}
|
|
@@ -54,6 +60,31 @@ export interface RunRemotionHubInitResult {
|
|
|
54
60
|
command: string;
|
|
55
61
|
args: string[];
|
|
56
62
|
};
|
|
63
|
+
skills: RemotionSkillsCommand & {
|
|
64
|
+
skipped: boolean;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface RunRemotionHubAddOptions {
|
|
68
|
+
item: string;
|
|
69
|
+
projectDir?: string;
|
|
70
|
+
namespace?: string;
|
|
71
|
+
registry?: string;
|
|
72
|
+
skipInstall?: boolean;
|
|
73
|
+
force?: boolean;
|
|
74
|
+
quiet?: boolean;
|
|
75
|
+
fetchImpl?: typeof fetch;
|
|
76
|
+
spawnImpl?: typeof spawnSync;
|
|
77
|
+
}
|
|
78
|
+
export interface RunRemotionHubAddResult {
|
|
79
|
+
name: string;
|
|
80
|
+
namespace: string;
|
|
81
|
+
slug: string;
|
|
82
|
+
type: string;
|
|
83
|
+
resolved: string;
|
|
84
|
+
written: string[];
|
|
85
|
+
dependencies: string[];
|
|
86
|
+
installedDependencies: string[];
|
|
87
|
+
snippet: string;
|
|
57
88
|
}
|
|
58
89
|
export interface ResolveRemotionHubRegistryOptions {
|
|
59
90
|
registry?: string;
|
|
@@ -62,5 +93,12 @@ export interface ResolveRemotionHubRegistryOptions {
|
|
|
62
93
|
localDefaultRegistry?: string;
|
|
63
94
|
}
|
|
64
95
|
export declare function resolveRemotionHubRegistry({ registry, env, generatedDefaultRegistry, localDefaultRegistry, }?: ResolveRemotionHubRegistryOptions): string;
|
|
96
|
+
export declare function buildRemotionSkillsCommand(): {
|
|
97
|
+
args: RemotionSkillsCommand["args"];
|
|
98
|
+
command: "npx";
|
|
99
|
+
display: "npx skills add remotion-dev/skills";
|
|
100
|
+
};
|
|
65
101
|
export declare function runRemotionHubInit(options?: RunRemotionHubInitOptions): RunRemotionHubInitResult;
|
|
102
|
+
export declare function runRemotionHubAdd(options: RunRemotionHubAddOptions): Promise<RunRemotionHubAddResult>;
|
|
103
|
+
export {};
|
|
66
104
|
//# sourceMappingURL=remotion-hub-init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/lib/remotion-hub-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAyB,MAAM,oBAAoB,CAAC;AAkBtE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,cAAc,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAChD,OAAO,EAAE;QACP,QAAQ,EAAE,YAAY,GAAG,YAAY,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ;
|
|
1
|
+
{"version":3,"file":"remotion-hub-init.d.ts","sourceRoot":"","sources":["../../src/lib/remotion-hub-init.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,11 @@ const CONFIG_FILE = 'remotion-hub.json';
|
|
|
7
7
|
const LOCK_FILE = 'remotion-hub.lock.json';
|
|
8
8
|
const DEFAULT_REGISTRY = 'http://localhost:3111';
|
|
9
9
|
const DEFAULT_NAMESPACE = 'doubledigit';
|
|
10
|
+
const REMOTION_SKILLS_COMMAND = {
|
|
11
|
+
command: 'npx',
|
|
12
|
+
args: ['skills', 'add', 'remotion-dev/skills'],
|
|
13
|
+
display: 'npx skills add remotion-dev/skills',
|
|
14
|
+
};
|
|
10
15
|
function toJson(value) {
|
|
11
16
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
12
17
|
}
|
|
@@ -174,6 +179,12 @@ function buildRemotionCreateCommand(projectDir) {
|
|
|
174
179
|
args: ['create-video@latest', '--yes', '--hello-world', projectDir],
|
|
175
180
|
};
|
|
176
181
|
}
|
|
182
|
+
export function buildRemotionSkillsCommand() {
|
|
183
|
+
return {
|
|
184
|
+
...REMOTION_SKILLS_COMMAND,
|
|
185
|
+
args: [...REMOTION_SKILLS_COMMAND.args],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
177
188
|
function assertRemotionCreateSucceeded(result, command, args) {
|
|
178
189
|
if (result.error) {
|
|
179
190
|
throw new Error(`Remotion project creation failed: ${result.error.message}`);
|
|
@@ -211,6 +222,152 @@ function loadConfig(projectDir) {
|
|
|
211
222
|
}
|
|
212
223
|
return JSON.parse(readFileSync(configPath, 'utf8'));
|
|
213
224
|
}
|
|
225
|
+
function normalizeRegistryBase(value) {
|
|
226
|
+
const trimmed = value.trim().replace(/\/+$/, '');
|
|
227
|
+
if (/^https?:\/\//i.test(trimmed))
|
|
228
|
+
return trimmed;
|
|
229
|
+
if (/^(localhost|127(?:\.\d{1,3}){3}|\[::1\])(?::|\/|$)/i.test(trimmed)) {
|
|
230
|
+
return `http://${trimmed}`;
|
|
231
|
+
}
|
|
232
|
+
return `https://${trimmed}`;
|
|
233
|
+
}
|
|
234
|
+
function parseItemRef(item, namespace) {
|
|
235
|
+
const trimmed = item.trim();
|
|
236
|
+
if (!trimmed)
|
|
237
|
+
throw new Error('Item name is required');
|
|
238
|
+
const parts = trimmed.split('/').filter(Boolean);
|
|
239
|
+
if (parts.length === 2) {
|
|
240
|
+
return { namespace: parts[0] ?? DEFAULT_NAMESPACE, slug: parts[1] ?? '' };
|
|
241
|
+
}
|
|
242
|
+
return { namespace: namespace || DEFAULT_NAMESPACE, slug: trimmed };
|
|
243
|
+
}
|
|
244
|
+
function registryPayloadUrl(config, namespace, slug, registryOverride) {
|
|
245
|
+
const base = normalizeRegistryBase(registryOverride || config.registry || DEFAULT_REGISTRY);
|
|
246
|
+
const encodedNamespace = encodeURIComponent(namespace);
|
|
247
|
+
const encodedSlug = encodeURIComponent(slug);
|
|
248
|
+
if (base.endsWith('/api/remotion-hub/r')) {
|
|
249
|
+
return `${base}/${encodedNamespace}/${encodedSlug}`;
|
|
250
|
+
}
|
|
251
|
+
return `${base}/api/remotion-hub/r/${encodedNamespace}/${encodedSlug}`;
|
|
252
|
+
}
|
|
253
|
+
function asStringArray(value) {
|
|
254
|
+
if (!Array.isArray(value))
|
|
255
|
+
return [];
|
|
256
|
+
return value.filter((item) => typeof item === 'string' && item.trim().length > 0);
|
|
257
|
+
}
|
|
258
|
+
function readRegistryPayload(value) {
|
|
259
|
+
const name = typeof value.name === 'string' && value.name.trim() ? value.name.trim() : '';
|
|
260
|
+
const type = typeof value.type === 'string' && value.type.trim() ? value.type.trim() : 'registry:component';
|
|
261
|
+
const version = typeof value.version === 'string' && value.version.trim() ? value.version.trim() : null;
|
|
262
|
+
const files = Array.isArray(value.files) ? value.files : [];
|
|
263
|
+
if (!name)
|
|
264
|
+
throw new Error('Registry payload is missing name');
|
|
265
|
+
if (files.length === 0)
|
|
266
|
+
throw new Error('Registry payload is missing files');
|
|
267
|
+
return {
|
|
268
|
+
name,
|
|
269
|
+
type,
|
|
270
|
+
version,
|
|
271
|
+
files,
|
|
272
|
+
dependencies: asStringArray(value.dependencies),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
async function fetchRegistryPayload(url, fetchImpl) {
|
|
276
|
+
const response = await fetchImpl(url);
|
|
277
|
+
const text = await response.text();
|
|
278
|
+
const parsed = text ? JSON.parse(text) : {};
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
const error = parsed && typeof parsed === 'object' && 'error' in parsed
|
|
281
|
+
? String(parsed.error)
|
|
282
|
+
: `Request failed with HTTP ${response.status}`;
|
|
283
|
+
throw new Error(error);
|
|
284
|
+
}
|
|
285
|
+
return readRegistryPayload(parsed);
|
|
286
|
+
}
|
|
287
|
+
function targetForRegistryFile(config, file) {
|
|
288
|
+
const explicitTarget = typeof file.target === 'string' ? file.target.trim() : '';
|
|
289
|
+
if (explicitTarget)
|
|
290
|
+
return explicitTarget;
|
|
291
|
+
const sourcePath = ensureRelativePath(typeof file.path === 'string' ? file.path : '', 'file.path');
|
|
292
|
+
const mappings = [
|
|
293
|
+
['components/', config.paths.components],
|
|
294
|
+
['scenes/', config.paths.scenes],
|
|
295
|
+
['overlays/', config.paths.overlays],
|
|
296
|
+
['transitions/', config.paths.transitions],
|
|
297
|
+
['assets/', config.paths.assets],
|
|
298
|
+
];
|
|
299
|
+
for (const [prefix, targetRoot] of mappings) {
|
|
300
|
+
if (sourcePath.startsWith(prefix)) {
|
|
301
|
+
return path.posix.join(targetRoot.replace(/\/+$/, ''), sourcePath.slice(prefix.length));
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return path.posix.join('src/remotion-hub', sourcePath);
|
|
305
|
+
}
|
|
306
|
+
function packageJsonDependencies(projectDir) {
|
|
307
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
308
|
+
if (!existsSync(packageJsonPath))
|
|
309
|
+
return new Set();
|
|
310
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
311
|
+
return new Set([
|
|
312
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
313
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
314
|
+
...Object.keys(pkg.peerDependencies ?? {}),
|
|
315
|
+
]);
|
|
316
|
+
}
|
|
317
|
+
function dependencyName(specifier) {
|
|
318
|
+
if (specifier.startsWith('@')) {
|
|
319
|
+
const [scope, name] = specifier.split('/');
|
|
320
|
+
return scope && name ? `${scope}/${name}` : specifier;
|
|
321
|
+
}
|
|
322
|
+
return specifier.split('@')[0] || specifier;
|
|
323
|
+
}
|
|
324
|
+
function installDependencies(projectDir, packageManager, dependencies, spawnImpl, quiet = false) {
|
|
325
|
+
if (dependencies.length === 0)
|
|
326
|
+
return [];
|
|
327
|
+
const installed = packageJsonDependencies(projectDir);
|
|
328
|
+
const missing = dependencies.filter((dependency) => !installed.has(dependencyName(dependency)));
|
|
329
|
+
if (missing.length === 0)
|
|
330
|
+
return [];
|
|
331
|
+
const command = packageManager;
|
|
332
|
+
const args = packageManager === 'npm'
|
|
333
|
+
? ['install', ...missing]
|
|
334
|
+
: ['add', ...missing];
|
|
335
|
+
const result = spawnImpl(command, args, {
|
|
336
|
+
cwd: projectDir,
|
|
337
|
+
stdio: quiet ? 'pipe' : 'inherit',
|
|
338
|
+
});
|
|
339
|
+
if (result.status !== 0) {
|
|
340
|
+
throw new Error(`Dependency install failed: ${command} ${args.join(' ')}`);
|
|
341
|
+
}
|
|
342
|
+
return missing;
|
|
343
|
+
}
|
|
344
|
+
function exportNameFromSource(source, fallback) {
|
|
345
|
+
const match = source.match(/export\s+(?:function|const|class)\s+([A-Z][A-Za-z0-9_]*)/);
|
|
346
|
+
if (match?.[1])
|
|
347
|
+
return match[1];
|
|
348
|
+
return fallback
|
|
349
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
352
|
+
.join('') || 'RemotionHubComponent';
|
|
353
|
+
}
|
|
354
|
+
function importPath(fromFile, toFile) {
|
|
355
|
+
const withoutExtension = toFile.replace(/\.[cm]?[tj]sx?$/, '');
|
|
356
|
+
let relative = normalizeSlashes(path.relative(path.dirname(fromFile), withoutExtension));
|
|
357
|
+
if (!relative.startsWith('.'))
|
|
358
|
+
relative = `./${relative}`;
|
|
359
|
+
return relative;
|
|
360
|
+
}
|
|
361
|
+
function buildSnippet(config, projectDir, name, primaryFile, source) {
|
|
362
|
+
const rootFile = resolveInsideProject(projectDir, config.remotion.root, 'remotion.root');
|
|
363
|
+
const exportName = exportNameFromSource(source, name);
|
|
364
|
+
const importFrom = importPath(rootFile, primaryFile);
|
|
365
|
+
return [
|
|
366
|
+
`import { ${exportName} } from '${importFrom}';`,
|
|
367
|
+
'',
|
|
368
|
+
`<Composition id="${name}" component={${exportName}} durationInFrames={180} fps={30} width={1920} height={1080} />`,
|
|
369
|
+
].join('\n');
|
|
370
|
+
}
|
|
214
371
|
export function runRemotionHubInit(options = {}) {
|
|
215
372
|
const projectDir = resolveProjectDir(options.projectDir);
|
|
216
373
|
const configPath = path.join(projectDir, CONFIG_FILE);
|
|
@@ -250,5 +407,82 @@ export function runRemotionHubInit(options = {}) {
|
|
|
250
407
|
created,
|
|
251
408
|
config,
|
|
252
409
|
remotionCreate,
|
|
410
|
+
skills: {
|
|
411
|
+
...buildRemotionSkillsCommand(),
|
|
412
|
+
skipped: options.skipSkills === true,
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
export async function runRemotionHubAdd(options) {
|
|
417
|
+
const projectDir = resolveProjectDir(options.projectDir);
|
|
418
|
+
const config = loadConfig(projectDir);
|
|
419
|
+
const itemRef = parseItemRef(options.item, options.namespace || config.namespace);
|
|
420
|
+
const resolved = registryPayloadUrl(config, itemRef.namespace, itemRef.slug, options.registry);
|
|
421
|
+
const payload = await fetchRegistryPayload(resolved, options.fetchImpl ?? fetch);
|
|
422
|
+
const lockPath = path.join(projectDir, LOCK_FILE);
|
|
423
|
+
const lock = readJsonFile(lockPath, defaultLock());
|
|
424
|
+
const written = [];
|
|
425
|
+
const filesToWrite = [];
|
|
426
|
+
const seenTargets = new Set();
|
|
427
|
+
let primaryFile = '';
|
|
428
|
+
let primarySource = '';
|
|
429
|
+
for (const file of payload.files) {
|
|
430
|
+
const content = typeof file.content === 'string' ? file.content : '';
|
|
431
|
+
if (!content)
|
|
432
|
+
throw new Error(`Registry file for ${payload.name} is missing content`);
|
|
433
|
+
const relativeTarget = targetForRegistryFile(config, file);
|
|
434
|
+
const destination = resolveInsideProject(projectDir, relativeTarget, 'file.target');
|
|
435
|
+
const relativePath = normalizeSlashes(path.relative(projectDir, destination));
|
|
436
|
+
if (seenTargets.has(relativePath)) {
|
|
437
|
+
throw new Error(`Registry payload contains duplicate target: ${relativePath}`);
|
|
438
|
+
}
|
|
439
|
+
if (existsSync(destination) && !options.force) {
|
|
440
|
+
throw new Error(`Refusing to overwrite existing file: ${relativePath}`);
|
|
441
|
+
}
|
|
442
|
+
seenTargets.add(relativePath);
|
|
443
|
+
filesToWrite.push({ destination, relativePath, content });
|
|
444
|
+
}
|
|
445
|
+
const installedDependencies = options.skipInstall
|
|
446
|
+
? []
|
|
447
|
+
: installDependencies(projectDir, config.packageManager, payload.dependencies, options.spawnImpl ?? spawnSync, options.quiet);
|
|
448
|
+
for (const file of filesToWrite) {
|
|
449
|
+
mkdirSync(path.dirname(file.destination), { recursive: true });
|
|
450
|
+
writeFileSync(file.destination, file.content, 'utf8');
|
|
451
|
+
written.push(file.relativePath);
|
|
452
|
+
if (!primaryFile && /\.[cm]?[tj]sx?$/.test(file.destination)) {
|
|
453
|
+
primaryFile = file.destination;
|
|
454
|
+
primarySource = file.content;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
for (const destination of filesToWrite.map((file) => file.destination)) {
|
|
458
|
+
if (!existsSync(destination)) {
|
|
459
|
+
throw new Error(`Failed to write file: ${normalizeSlashes(path.relative(projectDir, destination))}`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
lock.installed[payload.name] = {
|
|
463
|
+
version: payload.version,
|
|
464
|
+
type: payload.type,
|
|
465
|
+
namespace: itemRef.namespace,
|
|
466
|
+
slug: itemRef.slug,
|
|
467
|
+
resolved,
|
|
468
|
+
files: written,
|
|
469
|
+
dependencies: payload.dependencies,
|
|
470
|
+
installedAt: new Date().toISOString(),
|
|
471
|
+
};
|
|
472
|
+
writeJsonFile(lockPath, lock);
|
|
473
|
+
writeRegistryFile(projectDir, config, lock);
|
|
474
|
+
const snippet = primaryFile
|
|
475
|
+
? buildSnippet(config, projectDir, payload.name, primaryFile, primarySource)
|
|
476
|
+
: '';
|
|
477
|
+
return {
|
|
478
|
+
name: payload.name,
|
|
479
|
+
namespace: itemRef.namespace,
|
|
480
|
+
slug: itemRef.slug,
|
|
481
|
+
type: payload.type,
|
|
482
|
+
resolved,
|
|
483
|
+
written,
|
|
484
|
+
dependencies: payload.dependencies,
|
|
485
|
+
installedDependencies,
|
|
486
|
+
snippet,
|
|
253
487
|
};
|
|
254
488
|
}
|