@doubledigit/cli 0.6.0 → 0.8.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 +43 -9
- package/dist/codegen.js +1 -1
- package/dist/commands/actions.d.ts +2 -0
- package/dist/commands/actions.d.ts.map +1 -1
- package/dist/commands/actions.js +26 -7
- 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 +28 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/lib/actions-client.d.ts.map +1 -1
- package/dist/lib/actions-client.js +66 -35
- package/dist/lib/remotion-hub-init.d.ts +45 -0
- package/dist/lib/remotion-hub-init.d.ts.map +1 -1
- package/dist/lib/remotion-hub-init.js +266 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Double Digit is a pluggable Next.js/Payload developer control plane. The CLI is
|
|
|
9
9
|
Run the published package directly:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx @doubledigit/cli init my-project
|
|
12
|
+
npx @doubledigit/cli@latest init my-project
|
|
13
13
|
pnpm dlx @doubledigit/cli init my-project
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -77,7 +77,7 @@ dd browse # browse marketplace extensions
|
|
|
77
77
|
## New Project Bootstrap
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
npx @doubledigit/cli init my-project --yes
|
|
80
|
+
npx @doubledigit/cli@latest init my-project --yes
|
|
81
81
|
cd my-project
|
|
82
82
|
pnpm onboard
|
|
83
83
|
```
|
|
@@ -113,18 +113,50 @@ dd dev --port 3000
|
|
|
113
113
|
|
|
114
114
|
## Action Invocations
|
|
115
115
|
|
|
116
|
-
Use `dd actions` to discover or call enabled micro-app actions through the running app:
|
|
116
|
+
Use `dd actions` to discover or call enabled micro-app actions through the running app. External projects should use the published package through `npx @doubledigit/cli@latest` and should not assume a global `dd` binary exists:
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
npx @doubledigit/cli@latest actions remotion-hub
|
|
120
|
+
npx @doubledigit/cli@latest actions remotion-hub init temp-project
|
|
121
|
+
npx @doubledigit/cli@latest actions remotion-hub list-components --limit 5
|
|
122
|
+
npx @doubledigit/cli@latest actions remotion-hub search-components --query "animated chart" --limit 5
|
|
123
|
+
npx @doubledigit/cli@latest actions remotion-hub register-component --json-file component.json
|
|
122
124
|
```
|
|
123
125
|
|
|
124
126
|
Remotion Hub `init` is handled locally by the CLI because it creates files on the caller's machine. Other Remotion Hub actions, such as search and registry lookup, call the configured Double Digit app over HTTP.
|
|
125
127
|
|
|
126
128
|
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
129
|
|
|
130
|
+
After init, the CLI attempts to install both Remotion's project skills and the Double Digit Remotion Hub auxiliary skills from the created project directory:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx skills add remotion-dev/skills --all
|
|
134
|
+
npx skills add doubledigit/remotion-hub-skills --all
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Pass `--skip-skills` to skip skill installation. If skill installation fails, init still completes the project scaffold and prints exact retry commands. `--non-interactive` is accepted for automation scripts; the command is already prompt-free.
|
|
138
|
+
|
|
139
|
+
Register a component with simple JSON:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npx @doubledigit/cli@latest actions remotion-hub register-component --json-file component.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Minimal `component.json`:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"title": "Animated Chart",
|
|
150
|
+
"slug": "animated-chart",
|
|
151
|
+
"namespace": "doubledigit",
|
|
152
|
+
"kind": "component",
|
|
153
|
+
"description": "Animated chart scene.",
|
|
154
|
+
"tags": ["chart", "animation"],
|
|
155
|
+
"code": "export function AnimatedChart() { return null; }",
|
|
156
|
+
"metadata": {}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
128
160
|
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
161
|
|
|
130
162
|
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.
|
|
@@ -134,20 +166,22 @@ The published CLI embeds a hosted default from `DD_ACTIONS_DEFAULT_APP_URL` duri
|
|
|
134
166
|
The hosted Double Digit app is the default for npm users:
|
|
135
167
|
|
|
136
168
|
```bash
|
|
137
|
-
|
|
169
|
+
npx @doubledigit/cli@latest actions remotion-hub
|
|
138
170
|
```
|
|
139
171
|
|
|
140
172
|
This hosted default does not require a local checkout or running app.
|
|
141
173
|
|
|
174
|
+
Before relying on the hosted default in automation, run discovery as a preflight. If the hosted action endpoint returns HTTP 500 or is unreachable, use `DD_APP_URL` or `--url` to target a local or self-hosted Double Digit app until the hosted Remotion Hub is healthy.
|
|
175
|
+
|
|
142
176
|
Local development or self-hosted environments should override the target explicitly:
|
|
143
177
|
|
|
144
178
|
```bash
|
|
145
|
-
DD_APP_URL=http://localhost:3111
|
|
179
|
+
DD_APP_URL=http://localhost:3111 npx @doubledigit/cli@latest actions remotion-hub
|
|
146
180
|
```
|
|
147
181
|
|
|
148
182
|
In GitHub Actions or another CI/CD runner, provide `DD_ACTIONS_DEFAULT_APP_URL` or `DD_APP_URL` through the runner environment, variables, or secrets when building or publishing the CLI package. Do not rely on a local env file being present in CI.
|
|
149
183
|
|
|
150
|
-
GitHub or Infisical secrets are CI/CD inputs only. A local `npx @doubledigit/cli ...` command sees your shell environment and local env files, not repository secrets.
|
|
184
|
+
GitHub or Infisical secrets are CI/CD inputs only. A local `npx @doubledigit/cli@latest ...` command sees your shell environment and local env files, not repository secrets.
|
|
151
185
|
|
|
152
186
|
## Links
|
|
153
187
|
|
package/dist/codegen.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
const HEADER = `// ⚠️ AUTO-GENERATED by @doubledigit/cli sync
|
|
10
|
-
// Do not edit manually. Run \`dd sync\` or \`npx @doubledigit/cli sync\` to regenerate.
|
|
10
|
+
// Do not edit manually. Run \`dd sync\` or \`npx @doubledigit/cli@latest sync\` to regenerate.
|
|
11
11
|
`;
|
|
12
12
|
function toImportSpecifier(outputPath, entryFile) {
|
|
13
13
|
const relativePath = path.relative(path.dirname(outputPath), entryFile);
|
|
@@ -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":"AAoCA,wBAAgB,uBAAuB,WAKtC;AAoED,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',
|
|
@@ -15,6 +16,7 @@ const actionValueOptions = new Set([
|
|
|
15
16
|
'--namespace',
|
|
16
17
|
'--preview-type',
|
|
17
18
|
'--query',
|
|
19
|
+
'--json-file',
|
|
18
20
|
'--registry',
|
|
19
21
|
'--slug',
|
|
20
22
|
'--tag',
|
|
@@ -38,6 +40,7 @@ Usage:
|
|
|
38
40
|
Options:
|
|
39
41
|
--url, --app-url <url> App URL (default: DD_APP_URL, APP_URL, BETTER_AUTH_URL, or ${getDefaultActionsAppUrl()})
|
|
40
42
|
--json <json> JSON request body to send to the action
|
|
43
|
+
--json-file <path> Read the JSON request body from a file
|
|
41
44
|
--query <text> Set input.query
|
|
42
45
|
--limit <number> Set input.limit
|
|
43
46
|
--namespace <namespace> Set input namespace/filter
|
|
@@ -48,11 +51,14 @@ Options:
|
|
|
48
51
|
--tag, --tags <tags> Add one tag or comma-separated tags to filters.tags
|
|
49
52
|
|
|
50
53
|
Examples:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
npx @doubledigit/cli@latest actions remotion-hub
|
|
55
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --non-interactive
|
|
56
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --skip-skills
|
|
57
|
+
npx @doubledigit/cli@latest actions remotion-hub list-components --limit 5
|
|
58
|
+
npx @doubledigit/cli@latest actions remotion-hub add terminal-scene --dir my-video
|
|
59
|
+
npx @doubledigit/cli@latest actions remotion-hub search-components --query "animated chart" --limit 5
|
|
60
|
+
npx @doubledigit/cli@latest actions remotion-hub register-component --json-file component.json
|
|
61
|
+
npx @doubledigit/cli@latest actions remotion-hub get-registry-payload --json '{"namespace":"doubledigit","slug":"motion-strip"}'
|
|
56
62
|
`;
|
|
57
63
|
}
|
|
58
64
|
function readActionEnvFiles(paths) {
|
|
@@ -93,9 +99,9 @@ export function getActionPositionals(args) {
|
|
|
93
99
|
continue;
|
|
94
100
|
if (arg.startsWith('--')) {
|
|
95
101
|
const [flag, inlineValue] = arg.split(/=(.*)/s, 2);
|
|
96
|
-
if (flag === '--json' && inlineValue === undefined) {
|
|
102
|
+
if ((flag === '--json' || flag === '--json-file') && inlineValue === undefined) {
|
|
97
103
|
const next = args[i + 1];
|
|
98
|
-
if (next &&
|
|
104
|
+
if (next && !next.startsWith('--'))
|
|
99
105
|
i++;
|
|
100
106
|
}
|
|
101
107
|
else if (inlineValue === undefined && actionValueOptions.has(flag)) {
|
|
@@ -115,16 +121,29 @@ export function isRemotionHubInitAction(args) {
|
|
|
115
121
|
const positionals = getActionPositionals(args);
|
|
116
122
|
return positionals[0]?.value === 'remotion-hub' && positionals[1]?.value === 'init';
|
|
117
123
|
}
|
|
124
|
+
export function isRemotionHubAddAction(args) {
|
|
125
|
+
const positionals = getActionPositionals(args);
|
|
126
|
+
return positionals[0]?.value === 'remotion-hub' && positionals[1]?.value === 'add';
|
|
127
|
+
}
|
|
118
128
|
export function buildRemotionHubInitCommandArgs(args) {
|
|
119
129
|
const positionals = getActionPositionals(args);
|
|
120
130
|
const dropIndexes = new Set([positionals[0]?.index, positionals[1]?.index]);
|
|
121
131
|
return args.filter((_, index) => !dropIndexes.has(index));
|
|
122
132
|
}
|
|
133
|
+
export function buildRemotionHubAddCommandArgs(args) {
|
|
134
|
+
const positionals = getActionPositionals(args);
|
|
135
|
+
const dropIndexes = new Set([positionals[0]?.index, positionals[1]?.index]);
|
|
136
|
+
return args.filter((_, index) => !dropIndexes.has(index));
|
|
137
|
+
}
|
|
123
138
|
export async function actions(args) {
|
|
124
139
|
if (isRemotionHubInitAction(args)) {
|
|
125
140
|
runRemotionHubInitCommand(buildRemotionHubInitCommandArgs(args));
|
|
126
141
|
return;
|
|
127
142
|
}
|
|
143
|
+
if (isRemotionHubAddAction(args)) {
|
|
144
|
+
await runRemotionHubAddCommand(buildRemotionHubAddCommandArgs(args));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
128
147
|
const parsed = parseActionsArgs(args);
|
|
129
148
|
if (parsed.help || !parsed.microApp) {
|
|
130
149
|
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
|
+
npx @doubledigit/cli@latest actions remotion-hub add terminal-scene
|
|
82
|
+
npx @doubledigit/cli@latest actions remotion-hub add doubledigit/terminal-scene --dir ./my-video
|
|
83
|
+
npx @doubledigit/cli@latest 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;AAgCD,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,13 +78,17 @@ 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 install agent skills
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
npx @doubledigit/cli@latest actions remotion-hub init
|
|
88
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video
|
|
89
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --non-interactive
|
|
90
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --skip-skills
|
|
91
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --registry https://double-digit.example
|
|
86
92
|
`;
|
|
87
93
|
}
|
|
88
94
|
function printInit(result) {
|
|
@@ -95,6 +101,24 @@ function printInit(result) {
|
|
|
95
101
|
}
|
|
96
102
|
console.log('');
|
|
97
103
|
console.log(`Registry: ${result.config.registry}`);
|
|
104
|
+
if (!result.skills.skipped) {
|
|
105
|
+
const installed = result.skills.commands.filter((command) => command.success);
|
|
106
|
+
const failed = result.skills.commands.filter((command) => !command.success);
|
|
107
|
+
console.log('');
|
|
108
|
+
if (installed.length > 0) {
|
|
109
|
+
console.log('Installed agent skills:');
|
|
110
|
+
for (const command of installed) {
|
|
111
|
+
console.log(` ${command.display}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (failed.length > 0) {
|
|
115
|
+
console.log('Skill installation did not complete. The project scaffold is ready.');
|
|
116
|
+
console.log('Retry from the project directory:');
|
|
117
|
+
for (const command of failed) {
|
|
118
|
+
console.log(` ${command.display}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
98
122
|
}
|
|
99
123
|
export function runRemotionHubInitCommand(args) {
|
|
100
124
|
const parsed = parseArgs(args);
|
|
@@ -112,6 +136,7 @@ export function runRemotionHubInitCommand(args) {
|
|
|
112
136
|
namespace: stringFlag(parsed.flags, 'namespace'),
|
|
113
137
|
force: booleanFlag(parsed.flags, 'force'),
|
|
114
138
|
skipRemotionCreate: booleanFlag(parsed.flags, 'skip-remotion-create', 'hub-only'),
|
|
139
|
+
skipSkills: booleanFlag(parsed.flags, 'skip-skills'),
|
|
115
140
|
quiet: json,
|
|
116
141
|
});
|
|
117
142
|
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
|
|
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 npx @doubledigit/cli@latest actions remotion-hub init my-video --non-interactive\n npx @doubledigit/cli@latest actions remotion-hub init my-video --skip-skills\n npx @doubledigit/cli@latest 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,s4EAiDT,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,8 +45,9 @@ Examples:
|
|
|
45
45
|
dd run
|
|
46
46
|
dd dev
|
|
47
47
|
dd db status
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --non-interactive
|
|
49
|
+
npx @doubledigit/cli@latest actions remotion-hub init my-video --skip-skills
|
|
50
|
+
npx @doubledigit/cli@latest 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
|
|
52
53
|
dd add habit-tracker@community
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions-client.d.ts","sourceRoot":"","sources":["../../src/lib/actions-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions-client.d.ts","sourceRoot":"","sources":["../../src/lib/actions-client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,MAAM,WAAW,iCAAiC;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,GAAiB,EACjB,YAAY,EACZ,eAAe,GAChB,EAAE,iCAAiC,UAKnC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,GAAiB,EACjB,OAAY,EACZ,UAAU,GACX,EAAE,0BAA0B,UAS5B;AA4ED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CA6DlE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,UAS7C;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,WAK3C;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,YAAY,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAoBtI;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAiCjF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
1
2
|
function readUrlValue(value) {
|
|
2
3
|
const trimmed = value?.trim();
|
|
3
4
|
return trimmed || undefined;
|
|
@@ -25,14 +26,30 @@ function requireValue(args, index, flag) {
|
|
|
25
26
|
}
|
|
26
27
|
return value;
|
|
27
28
|
}
|
|
28
|
-
function parseJson(value) {
|
|
29
|
+
function parseJson(value, label = '--json') {
|
|
29
30
|
try {
|
|
30
31
|
return JSON.parse(value);
|
|
31
32
|
}
|
|
32
33
|
catch {
|
|
33
|
-
throw new Error(
|
|
34
|
+
throw new Error(`${label} must be valid JSON`);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
37
|
+
function readJsonFile(filePath) {
|
|
38
|
+
try {
|
|
39
|
+
return readFileSync(filePath, 'utf8');
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
43
|
+
throw new Error(`Unable to read JSON file ${filePath}: ${detail}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function parseJsonValue(value, label) {
|
|
47
|
+
if (value.startsWith('@') && value.length > 1) {
|
|
48
|
+
const filePath = value.slice(1);
|
|
49
|
+
return parseJson(readJsonFile(filePath), `${label} ${value}`);
|
|
50
|
+
}
|
|
51
|
+
return parseJson(value, label);
|
|
52
|
+
}
|
|
36
53
|
function asFilters(input) {
|
|
37
54
|
const filters = input.filters;
|
|
38
55
|
if (filters && typeof filters === 'object' && !Array.isArray(filters)) {
|
|
@@ -78,52 +95,55 @@ export function parseActionsArgs(args) {
|
|
|
78
95
|
const arg = args[i];
|
|
79
96
|
if (arg === '--help' || arg === '-h') {
|
|
80
97
|
help = true;
|
|
98
|
+
continue;
|
|
81
99
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
if (!arg.startsWith('--')) {
|
|
101
|
+
positional.push(arg);
|
|
102
|
+
continue;
|
|
85
103
|
}
|
|
86
|
-
|
|
87
|
-
|
|
104
|
+
const [flag, inlineValue] = arg.split(/=(.*)/s, 2);
|
|
105
|
+
const readValue = () => {
|
|
106
|
+
if (inlineValue !== undefined)
|
|
107
|
+
return inlineValue;
|
|
108
|
+
const value = requireValue(args, i, flag);
|
|
88
109
|
i++;
|
|
110
|
+
return value;
|
|
111
|
+
};
|
|
112
|
+
if (flag === '--url' || flag === '--app-url') {
|
|
113
|
+
appUrl = readValue();
|
|
89
114
|
}
|
|
90
|
-
else if (
|
|
91
|
-
|
|
92
|
-
i++;
|
|
115
|
+
else if (flag === '--json') {
|
|
116
|
+
Object.assign(input, parseJsonValue(readValue(), '--json'));
|
|
93
117
|
}
|
|
94
|
-
else if (
|
|
95
|
-
|
|
96
|
-
i++;
|
|
118
|
+
else if (flag === '--json-file') {
|
|
119
|
+
Object.assign(input, parseJson(readJsonFile(readValue()), '--json-file'));
|
|
97
120
|
}
|
|
98
|
-
else if (
|
|
99
|
-
setInputValue(input, '
|
|
100
|
-
i++;
|
|
121
|
+
else if (flag === '--query') {
|
|
122
|
+
setInputValue(input, 'query', readValue());
|
|
101
123
|
}
|
|
102
|
-
else if (
|
|
103
|
-
setInputValue(input, '
|
|
104
|
-
i++;
|
|
124
|
+
else if (flag === '--limit') {
|
|
125
|
+
setInputValue(input, 'limit', readValue());
|
|
105
126
|
}
|
|
106
|
-
else if (
|
|
107
|
-
setInputValue(input, '
|
|
108
|
-
i++;
|
|
127
|
+
else if (flag === '--namespace') {
|
|
128
|
+
setInputValue(input, 'namespace', readValue());
|
|
109
129
|
}
|
|
110
|
-
else if (
|
|
111
|
-
setInputValue(input, '
|
|
112
|
-
i++;
|
|
130
|
+
else if (flag === '--slug') {
|
|
131
|
+
setInputValue(input, 'slug', readValue());
|
|
113
132
|
}
|
|
114
|
-
else if (
|
|
115
|
-
setInputValue(input, '
|
|
116
|
-
i++;
|
|
133
|
+
else if (flag === '--id-or-slug') {
|
|
134
|
+
setInputValue(input, 'idOrSlug', readValue());
|
|
117
135
|
}
|
|
118
|
-
else if (
|
|
119
|
-
|
|
120
|
-
i++;
|
|
136
|
+
else if (flag === '--kind') {
|
|
137
|
+
setInputValue(input, 'kind', readValue());
|
|
121
138
|
}
|
|
122
|
-
else if (
|
|
123
|
-
|
|
139
|
+
else if (flag === '--preview-type') {
|
|
140
|
+
setInputValue(input, 'previewType', readValue());
|
|
141
|
+
}
|
|
142
|
+
else if (flag === '--tag' || flag === '--tags') {
|
|
143
|
+
addTag(input, readValue());
|
|
124
144
|
}
|
|
125
145
|
else {
|
|
126
|
-
|
|
146
|
+
throw new Error(`Unknown option: ${flag}`);
|
|
127
147
|
}
|
|
128
148
|
}
|
|
129
149
|
return {
|
|
@@ -181,7 +201,18 @@ export async function fetchActionRequest(request) {
|
|
|
181
201
|
'Set DD_APP_URL to the running Double Digit app URL, or pass --url.');
|
|
182
202
|
}
|
|
183
203
|
const text = await response.text();
|
|
184
|
-
|
|
204
|
+
let payload = null;
|
|
205
|
+
if (text) {
|
|
206
|
+
try {
|
|
207
|
+
payload = JSON.parse(text);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
if (!response.ok) {
|
|
211
|
+
throw new Error(`Request failed with HTTP ${response.status}`);
|
|
212
|
+
}
|
|
213
|
+
throw new Error(`Expected JSON response from ${request.url}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
185
216
|
if (!response.ok) {
|
|
186
217
|
const error = payload && typeof payload === 'object' && 'error' in payload
|
|
187
218
|
? String(payload.error)
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
type RemotionSkillsCommand = {
|
|
3
|
+
command: 'npx';
|
|
4
|
+
args: string[];
|
|
5
|
+
display: string;
|
|
6
|
+
};
|
|
7
|
+
type RemotionSkillsInstallResult = RemotionSkillsCommand & {
|
|
8
|
+
skipped: boolean;
|
|
9
|
+
success: boolean;
|
|
10
|
+
status: number | null;
|
|
11
|
+
error?: string;
|
|
12
|
+
};
|
|
2
13
|
export interface RemotionHubConfig {
|
|
3
14
|
$schema: string;
|
|
4
15
|
registry: string;
|
|
@@ -40,6 +51,7 @@ export interface RunRemotionHubInitOptions {
|
|
|
40
51
|
namespace?: string;
|
|
41
52
|
force?: boolean;
|
|
42
53
|
skipRemotionCreate?: boolean;
|
|
54
|
+
skipSkills?: boolean;
|
|
43
55
|
quiet?: boolean;
|
|
44
56
|
spawnImpl?: typeof spawnSync;
|
|
45
57
|
}
|
|
@@ -54,6 +66,32 @@ export interface RunRemotionHubInitResult {
|
|
|
54
66
|
command: string;
|
|
55
67
|
args: string[];
|
|
56
68
|
};
|
|
69
|
+
skills: {
|
|
70
|
+
skipped: boolean;
|
|
71
|
+
commands: RemotionSkillsInstallResult[];
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface RunRemotionHubAddOptions {
|
|
75
|
+
item: string;
|
|
76
|
+
projectDir?: string;
|
|
77
|
+
namespace?: string;
|
|
78
|
+
registry?: string;
|
|
79
|
+
skipInstall?: boolean;
|
|
80
|
+
force?: boolean;
|
|
81
|
+
quiet?: boolean;
|
|
82
|
+
fetchImpl?: typeof fetch;
|
|
83
|
+
spawnImpl?: typeof spawnSync;
|
|
84
|
+
}
|
|
85
|
+
export interface RunRemotionHubAddResult {
|
|
86
|
+
name: string;
|
|
87
|
+
namespace: string;
|
|
88
|
+
slug: string;
|
|
89
|
+
type: string;
|
|
90
|
+
resolved: string;
|
|
91
|
+
written: string[];
|
|
92
|
+
dependencies: string[];
|
|
93
|
+
installedDependencies: string[];
|
|
94
|
+
snippet: string;
|
|
57
95
|
}
|
|
58
96
|
export interface ResolveRemotionHubRegistryOptions {
|
|
59
97
|
registry?: string;
|
|
@@ -62,5 +100,12 @@ export interface ResolveRemotionHubRegistryOptions {
|
|
|
62
100
|
localDefaultRegistry?: string;
|
|
63
101
|
}
|
|
64
102
|
export declare function resolveRemotionHubRegistry({ registry, env, generatedDefaultRegistry, localDefaultRegistry, }?: ResolveRemotionHubRegistryOptions): string;
|
|
103
|
+
export declare function buildRemotionSkillsCommands(): {
|
|
104
|
+
args: string[];
|
|
105
|
+
command: "npx";
|
|
106
|
+
display: string;
|
|
107
|
+
}[];
|
|
65
108
|
export declare function runRemotionHubInit(options?: RunRemotionHubInitOptions): RunRemotionHubInitResult;
|
|
109
|
+
export declare function runRemotionHubAdd(options: RunRemotionHubAddOptions): Promise<RunRemotionHubAddResult>;
|
|
110
|
+
export {};
|
|
66
111
|
//# 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,18 @@ 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_COMMANDS = [
|
|
11
|
+
{
|
|
12
|
+
command: 'npx',
|
|
13
|
+
args: ['skills', 'add', 'remotion-dev/skills', '--all'],
|
|
14
|
+
display: 'npx skills add remotion-dev/skills --all',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
command: 'npx',
|
|
18
|
+
args: ['skills', 'add', 'doubledigit/remotion-hub-skills', '--all'],
|
|
19
|
+
display: 'npx skills add doubledigit/remotion-hub-skills --all',
|
|
20
|
+
},
|
|
21
|
+
];
|
|
10
22
|
function toJson(value) {
|
|
11
23
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
12
24
|
}
|
|
@@ -174,6 +186,36 @@ function buildRemotionCreateCommand(projectDir) {
|
|
|
174
186
|
args: ['create-video@latest', '--yes', '--hello-world', projectDir],
|
|
175
187
|
};
|
|
176
188
|
}
|
|
189
|
+
export function buildRemotionSkillsCommands() {
|
|
190
|
+
return REMOTION_SKILLS_COMMANDS.map((command) => ({
|
|
191
|
+
...command,
|
|
192
|
+
args: [...command.args],
|
|
193
|
+
}));
|
|
194
|
+
}
|
|
195
|
+
function runRemotionSkillsInstall(projectDir, options) {
|
|
196
|
+
const commands = buildRemotionSkillsCommands();
|
|
197
|
+
if (options.skipSkills) {
|
|
198
|
+
return commands.map((command) => ({
|
|
199
|
+
...command,
|
|
200
|
+
skipped: true,
|
|
201
|
+
success: false,
|
|
202
|
+
status: null,
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
return commands.map((command) => {
|
|
206
|
+
const result = (options.spawnImpl ?? spawnSync)(command.command, command.args, {
|
|
207
|
+
cwd: projectDir,
|
|
208
|
+
stdio: options.quiet ? 'pipe' : 'inherit',
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
...command,
|
|
212
|
+
skipped: false,
|
|
213
|
+
success: !result.error && result.status === 0,
|
|
214
|
+
status: result.status,
|
|
215
|
+
error: result.error?.message,
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
}
|
|
177
219
|
function assertRemotionCreateSucceeded(result, command, args) {
|
|
178
220
|
if (result.error) {
|
|
179
221
|
throw new Error(`Remotion project creation failed: ${result.error.message}`);
|
|
@@ -211,6 +253,152 @@ function loadConfig(projectDir) {
|
|
|
211
253
|
}
|
|
212
254
|
return JSON.parse(readFileSync(configPath, 'utf8'));
|
|
213
255
|
}
|
|
256
|
+
function normalizeRegistryBase(value) {
|
|
257
|
+
const trimmed = value.trim().replace(/\/+$/, '');
|
|
258
|
+
if (/^https?:\/\//i.test(trimmed))
|
|
259
|
+
return trimmed;
|
|
260
|
+
if (/^(localhost|127(?:\.\d{1,3}){3}|\[::1\])(?::|\/|$)/i.test(trimmed)) {
|
|
261
|
+
return `http://${trimmed}`;
|
|
262
|
+
}
|
|
263
|
+
return `https://${trimmed}`;
|
|
264
|
+
}
|
|
265
|
+
function parseItemRef(item, namespace) {
|
|
266
|
+
const trimmed = item.trim();
|
|
267
|
+
if (!trimmed)
|
|
268
|
+
throw new Error('Item name is required');
|
|
269
|
+
const parts = trimmed.split('/').filter(Boolean);
|
|
270
|
+
if (parts.length === 2) {
|
|
271
|
+
return { namespace: parts[0] ?? DEFAULT_NAMESPACE, slug: parts[1] ?? '' };
|
|
272
|
+
}
|
|
273
|
+
return { namespace: namespace || DEFAULT_NAMESPACE, slug: trimmed };
|
|
274
|
+
}
|
|
275
|
+
function registryPayloadUrl(config, namespace, slug, registryOverride) {
|
|
276
|
+
const base = normalizeRegistryBase(registryOverride || config.registry || DEFAULT_REGISTRY);
|
|
277
|
+
const encodedNamespace = encodeURIComponent(namespace);
|
|
278
|
+
const encodedSlug = encodeURIComponent(slug);
|
|
279
|
+
if (base.endsWith('/api/remotion-hub/r')) {
|
|
280
|
+
return `${base}/${encodedNamespace}/${encodedSlug}`;
|
|
281
|
+
}
|
|
282
|
+
return `${base}/api/remotion-hub/r/${encodedNamespace}/${encodedSlug}`;
|
|
283
|
+
}
|
|
284
|
+
function asStringArray(value) {
|
|
285
|
+
if (!Array.isArray(value))
|
|
286
|
+
return [];
|
|
287
|
+
return value.filter((item) => typeof item === 'string' && item.trim().length > 0);
|
|
288
|
+
}
|
|
289
|
+
function readRegistryPayload(value) {
|
|
290
|
+
const name = typeof value.name === 'string' && value.name.trim() ? value.name.trim() : '';
|
|
291
|
+
const type = typeof value.type === 'string' && value.type.trim() ? value.type.trim() : 'registry:component';
|
|
292
|
+
const version = typeof value.version === 'string' && value.version.trim() ? value.version.trim() : null;
|
|
293
|
+
const files = Array.isArray(value.files) ? value.files : [];
|
|
294
|
+
if (!name)
|
|
295
|
+
throw new Error('Registry payload is missing name');
|
|
296
|
+
if (files.length === 0)
|
|
297
|
+
throw new Error('Registry payload is missing files');
|
|
298
|
+
return {
|
|
299
|
+
name,
|
|
300
|
+
type,
|
|
301
|
+
version,
|
|
302
|
+
files,
|
|
303
|
+
dependencies: asStringArray(value.dependencies),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
async function fetchRegistryPayload(url, fetchImpl) {
|
|
307
|
+
const response = await fetchImpl(url);
|
|
308
|
+
const text = await response.text();
|
|
309
|
+
const parsed = text ? JSON.parse(text) : {};
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
const error = parsed && typeof parsed === 'object' && 'error' in parsed
|
|
312
|
+
? String(parsed.error)
|
|
313
|
+
: `Request failed with HTTP ${response.status}`;
|
|
314
|
+
throw new Error(error);
|
|
315
|
+
}
|
|
316
|
+
return readRegistryPayload(parsed);
|
|
317
|
+
}
|
|
318
|
+
function targetForRegistryFile(config, file) {
|
|
319
|
+
const explicitTarget = typeof file.target === 'string' ? file.target.trim() : '';
|
|
320
|
+
if (explicitTarget)
|
|
321
|
+
return explicitTarget;
|
|
322
|
+
const sourcePath = ensureRelativePath(typeof file.path === 'string' ? file.path : '', 'file.path');
|
|
323
|
+
const mappings = [
|
|
324
|
+
['components/', config.paths.components],
|
|
325
|
+
['scenes/', config.paths.scenes],
|
|
326
|
+
['overlays/', config.paths.overlays],
|
|
327
|
+
['transitions/', config.paths.transitions],
|
|
328
|
+
['assets/', config.paths.assets],
|
|
329
|
+
];
|
|
330
|
+
for (const [prefix, targetRoot] of mappings) {
|
|
331
|
+
if (sourcePath.startsWith(prefix)) {
|
|
332
|
+
return path.posix.join(targetRoot.replace(/\/+$/, ''), sourcePath.slice(prefix.length));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return path.posix.join('src/remotion-hub', sourcePath);
|
|
336
|
+
}
|
|
337
|
+
function packageJsonDependencies(projectDir) {
|
|
338
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
339
|
+
if (!existsSync(packageJsonPath))
|
|
340
|
+
return new Set();
|
|
341
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
342
|
+
return new Set([
|
|
343
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
344
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
345
|
+
...Object.keys(pkg.peerDependencies ?? {}),
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
function dependencyName(specifier) {
|
|
349
|
+
if (specifier.startsWith('@')) {
|
|
350
|
+
const [scope, name] = specifier.split('/');
|
|
351
|
+
return scope && name ? `${scope}/${name}` : specifier;
|
|
352
|
+
}
|
|
353
|
+
return specifier.split('@')[0] || specifier;
|
|
354
|
+
}
|
|
355
|
+
function installDependencies(projectDir, packageManager, dependencies, spawnImpl, quiet = false) {
|
|
356
|
+
if (dependencies.length === 0)
|
|
357
|
+
return [];
|
|
358
|
+
const installed = packageJsonDependencies(projectDir);
|
|
359
|
+
const missing = dependencies.filter((dependency) => !installed.has(dependencyName(dependency)));
|
|
360
|
+
if (missing.length === 0)
|
|
361
|
+
return [];
|
|
362
|
+
const command = packageManager;
|
|
363
|
+
const args = packageManager === 'npm'
|
|
364
|
+
? ['install', ...missing]
|
|
365
|
+
: ['add', ...missing];
|
|
366
|
+
const result = spawnImpl(command, args, {
|
|
367
|
+
cwd: projectDir,
|
|
368
|
+
stdio: quiet ? 'pipe' : 'inherit',
|
|
369
|
+
});
|
|
370
|
+
if (result.status !== 0) {
|
|
371
|
+
throw new Error(`Dependency install failed: ${command} ${args.join(' ')}`);
|
|
372
|
+
}
|
|
373
|
+
return missing;
|
|
374
|
+
}
|
|
375
|
+
function exportNameFromSource(source, fallback) {
|
|
376
|
+
const match = source.match(/export\s+(?:function|const|class)\s+([A-Z][A-Za-z0-9_]*)/);
|
|
377
|
+
if (match?.[1])
|
|
378
|
+
return match[1];
|
|
379
|
+
return fallback
|
|
380
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
381
|
+
.filter(Boolean)
|
|
382
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
383
|
+
.join('') || 'RemotionHubComponent';
|
|
384
|
+
}
|
|
385
|
+
function importPath(fromFile, toFile) {
|
|
386
|
+
const withoutExtension = toFile.replace(/\.[cm]?[tj]sx?$/, '');
|
|
387
|
+
let relative = normalizeSlashes(path.relative(path.dirname(fromFile), withoutExtension));
|
|
388
|
+
if (!relative.startsWith('.'))
|
|
389
|
+
relative = `./${relative}`;
|
|
390
|
+
return relative;
|
|
391
|
+
}
|
|
392
|
+
function buildSnippet(config, projectDir, name, primaryFile, source) {
|
|
393
|
+
const rootFile = resolveInsideProject(projectDir, config.remotion.root, 'remotion.root');
|
|
394
|
+
const exportName = exportNameFromSource(source, name);
|
|
395
|
+
const importFrom = importPath(rootFile, primaryFile);
|
|
396
|
+
return [
|
|
397
|
+
`import { ${exportName} } from '${importFrom}';`,
|
|
398
|
+
'',
|
|
399
|
+
`<Composition id="${name}" component={${exportName}} durationInFrames={180} fps={30} width={1920} height={1080} />`,
|
|
400
|
+
].join('\n');
|
|
401
|
+
}
|
|
214
402
|
export function runRemotionHubInit(options = {}) {
|
|
215
403
|
const projectDir = resolveProjectDir(options.projectDir);
|
|
216
404
|
const configPath = path.join(projectDir, CONFIG_FILE);
|
|
@@ -243,6 +431,7 @@ export function runRemotionHubInit(options = {}) {
|
|
|
243
431
|
const lock = readJsonFile(lockPath, defaultLock());
|
|
244
432
|
writeRegistryFile(projectDir, config, lock);
|
|
245
433
|
created.push(config.paths.registry);
|
|
434
|
+
const skills = runRemotionSkillsInstall(projectDir, options);
|
|
246
435
|
return {
|
|
247
436
|
projectDir,
|
|
248
437
|
configPath,
|
|
@@ -250,5 +439,82 @@ export function runRemotionHubInit(options = {}) {
|
|
|
250
439
|
created,
|
|
251
440
|
config,
|
|
252
441
|
remotionCreate,
|
|
442
|
+
skills: {
|
|
443
|
+
skipped: options.skipSkills === true,
|
|
444
|
+
commands: skills,
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
export async function runRemotionHubAdd(options) {
|
|
449
|
+
const projectDir = resolveProjectDir(options.projectDir);
|
|
450
|
+
const config = loadConfig(projectDir);
|
|
451
|
+
const itemRef = parseItemRef(options.item, options.namespace || config.namespace);
|
|
452
|
+
const resolved = registryPayloadUrl(config, itemRef.namespace, itemRef.slug, options.registry);
|
|
453
|
+
const payload = await fetchRegistryPayload(resolved, options.fetchImpl ?? fetch);
|
|
454
|
+
const lockPath = path.join(projectDir, LOCK_FILE);
|
|
455
|
+
const lock = readJsonFile(lockPath, defaultLock());
|
|
456
|
+
const written = [];
|
|
457
|
+
const filesToWrite = [];
|
|
458
|
+
const seenTargets = new Set();
|
|
459
|
+
let primaryFile = '';
|
|
460
|
+
let primarySource = '';
|
|
461
|
+
for (const file of payload.files) {
|
|
462
|
+
const content = typeof file.content === 'string' ? file.content : '';
|
|
463
|
+
if (!content)
|
|
464
|
+
throw new Error(`Registry file for ${payload.name} is missing content`);
|
|
465
|
+
const relativeTarget = targetForRegistryFile(config, file);
|
|
466
|
+
const destination = resolveInsideProject(projectDir, relativeTarget, 'file.target');
|
|
467
|
+
const relativePath = normalizeSlashes(path.relative(projectDir, destination));
|
|
468
|
+
if (seenTargets.has(relativePath)) {
|
|
469
|
+
throw new Error(`Registry payload contains duplicate target: ${relativePath}`);
|
|
470
|
+
}
|
|
471
|
+
if (existsSync(destination) && !options.force) {
|
|
472
|
+
throw new Error(`Refusing to overwrite existing file: ${relativePath}`);
|
|
473
|
+
}
|
|
474
|
+
seenTargets.add(relativePath);
|
|
475
|
+
filesToWrite.push({ destination, relativePath, content });
|
|
476
|
+
}
|
|
477
|
+
const installedDependencies = options.skipInstall
|
|
478
|
+
? []
|
|
479
|
+
: installDependencies(projectDir, config.packageManager, payload.dependencies, options.spawnImpl ?? spawnSync, options.quiet);
|
|
480
|
+
for (const file of filesToWrite) {
|
|
481
|
+
mkdirSync(path.dirname(file.destination), { recursive: true });
|
|
482
|
+
writeFileSync(file.destination, file.content, 'utf8');
|
|
483
|
+
written.push(file.relativePath);
|
|
484
|
+
if (!primaryFile && /\.[cm]?[tj]sx?$/.test(file.destination)) {
|
|
485
|
+
primaryFile = file.destination;
|
|
486
|
+
primarySource = file.content;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
for (const destination of filesToWrite.map((file) => file.destination)) {
|
|
490
|
+
if (!existsSync(destination)) {
|
|
491
|
+
throw new Error(`Failed to write file: ${normalizeSlashes(path.relative(projectDir, destination))}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
lock.installed[payload.name] = {
|
|
495
|
+
version: payload.version,
|
|
496
|
+
type: payload.type,
|
|
497
|
+
namespace: itemRef.namespace,
|
|
498
|
+
slug: itemRef.slug,
|
|
499
|
+
resolved,
|
|
500
|
+
files: written,
|
|
501
|
+
dependencies: payload.dependencies,
|
|
502
|
+
installedAt: new Date().toISOString(),
|
|
503
|
+
};
|
|
504
|
+
writeJsonFile(lockPath, lock);
|
|
505
|
+
writeRegistryFile(projectDir, config, lock);
|
|
506
|
+
const snippet = primaryFile
|
|
507
|
+
? buildSnippet(config, projectDir, payload.name, primaryFile, primarySource)
|
|
508
|
+
: '';
|
|
509
|
+
return {
|
|
510
|
+
name: payload.name,
|
|
511
|
+
namespace: itemRef.namespace,
|
|
512
|
+
slug: itemRef.slug,
|
|
513
|
+
type: payload.type,
|
|
514
|
+
resolved,
|
|
515
|
+
written,
|
|
516
|
+
dependencies: payload.dependencies,
|
|
517
|
+
installedDependencies,
|
|
518
|
+
snippet,
|
|
253
519
|
};
|
|
254
520
|
}
|