@remotion/studio-server 4.0.533 → 4.0.534

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.
Files changed (42) hide show
  1. package/dist/detect-outdated-remotion-skills.d.ts +4 -0
  2. package/dist/detect-outdated-remotion-skills.js +3 -2
  3. package/dist/helpers/coding-agent-registry.d.ts +1 -0
  4. package/dist/helpers/coding-agent-registry.js +22 -1
  5. package/dist/helpers/editor-registry.d.ts +1 -0
  6. package/dist/helpers/editor-registry.js +24 -1
  7. package/dist/helpers/open-in-editor.d.ts +1 -1
  8. package/dist/helpers/open-in-editor.js +65 -83
  9. package/dist/helpers/running-processes.d.ts +12 -0
  10. package/dist/helpers/running-processes.js +88 -0
  11. package/dist/helpers/video-config-numeric-expression.js +29 -20
  12. package/dist/helpers/video-config-values.d.ts +6 -3
  13. package/dist/helpers/video-config-values.js +42 -26
  14. package/dist/preview-server/api-routes.js +4 -0
  15. package/dist/preview-server/routes/add-sequence-keyframe.js +0 -1
  16. package/dist/preview-server/routes/can-update-effect-props.d.ts +4 -6
  17. package/dist/preview-server/routes/can-update-effect-props.js +5 -28
  18. package/dist/preview-server/routes/can-update-sequence-props.d.ts +6 -8
  19. package/dist/preview-server/routes/can-update-sequence-props.js +11 -12
  20. package/dist/preview-server/routes/default-coding-agent.js +2 -0
  21. package/dist/preview-server/routes/default-editor.js +5 -1
  22. package/dist/preview-server/routes/delete-keyframes.d.ts +2 -2
  23. package/dist/preview-server/routes/delete-keyframes.js +0 -1
  24. package/dist/preview-server/routes/insert-element.js +17 -7
  25. package/dist/preview-server/routes/install-remotion-skill.d.ts +2 -1
  26. package/dist/preview-server/routes/install-remotion-skill.js +87 -56
  27. package/dist/preview-server/routes/open-in-editor.js +1 -1
  28. package/dist/preview-server/routes/remotion-skills-info.d.ts +2 -1
  29. package/dist/preview-server/routes/remotion-skills-info.js +57 -3
  30. package/dist/preview-server/routes/save-sequence-props.js +0 -1
  31. package/dist/preview-server/routes/shared-memory-capture-support.d.ts +3 -0
  32. package/dist/preview-server/routes/shared-memory-capture-support.js +13 -0
  33. package/dist/preview-server/routes/subscribe-to-sequence-props.js +1 -2
  34. package/dist/preview-server/routes/unsubscribe-from-sequence-props.js +0 -1
  35. package/dist/preview-server/routes/update-sequence-keyframe-settings.js +0 -1
  36. package/dist/preview-server/routes/wrap-node.js +13 -4
  37. package/dist/preview-server/sequence-props-watchers.d.ts +3 -5
  38. package/dist/preview-server/sequence-props-watchers.js +9 -17
  39. package/dist/preview-server/update-available.js +17 -0
  40. package/dist/routes.js +3 -1
  41. package/dist/start-studio.js +7 -3
  42. package/package.json +8 -8
@@ -15,6 +15,10 @@ export type RemotionSkillsStatus = {
15
15
  outdatedSkillNames: RemotionSkillName[];
16
16
  };
17
17
  export declare const parseRemotionSkillVersion: (contents: string) => string | null;
18
+ export declare const readRemotionSkill: (skillFile: string) => {
19
+ installed: boolean;
20
+ version: string | null;
21
+ };
18
22
  export declare const getRemotionSkillsDirectories: ({ cwd, homeDirectory, }: {
19
23
  cwd: string;
20
24
  homeDirectory: string;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.detectOutdatedRemotionSkills = exports.getRemotionSkillsDirectories = exports.parseRemotionSkillVersion = void 0;
6
+ exports.detectOutdatedRemotionSkills = exports.getRemotionSkillsDirectories = exports.readRemotionSkill = exports.parseRemotionSkillVersion = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_os_1 = require("node:os");
9
9
  const node_path_1 = __importDefault(require("node:path"));
@@ -34,10 +34,11 @@ const readRemotionSkill = (skillFile) => {
34
34
  return { installed: true, version: null };
35
35
  }
36
36
  };
37
+ exports.readRemotionSkill = readRemotionSkill;
37
38
  const getStatusForSkillsDirectory = ({ currentVersion, scope, skillsDirectory, }) => {
38
39
  const installedSkills = new Map();
39
40
  for (const skillName of remotion_skill_names_1.remotionSkillNames) {
40
- installedSkills.set(skillName, readRemotionSkill(node_path_1.default.join(skillsDirectory, skillName, 'SKILL.md')));
41
+ installedSkills.set(skillName, (0, exports.readRemotionSkill)(node_path_1.default.join(skillsDirectory, skillName, 'SKILL.md')));
41
42
  }
42
43
  if ([...installedSkills.values()].every((skill) => !skill.installed)) {
43
44
  return { type: 'not-installed', scope, skillsDirectory };
@@ -23,6 +23,7 @@ export type CodingAgentDiscoveryContext = {
23
23
  };
24
24
  export declare const discoverAvailableCodingAgents: (context: CodingAgentDiscoveryContext) => Promise<readonly InstalledCodingAgent[]>;
25
25
  export declare const getAvailableCodingAgents: () => Promise<readonly InstalledCodingAgent[]>;
26
+ export declare const getRunningCodingAgents: (installedCodingAgents: readonly InstalledCodingAgent[]) => Promise<readonly ("claude-code" | "codex" | "copilot" | "cursor")[]>;
26
27
  export declare const getCodingAgentLaunchCommand: ({ codingAgent, projectPath, }: {
27
28
  codingAgent: InstalledCodingAgent;
28
29
  projectPath: string;
@@ -3,13 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.launchCodingAgent = exports.getCodingAgentLaunchCommands = exports.getCodingAgentLaunchCommand = exports.getAvailableCodingAgents = exports.discoverAvailableCodingAgents = void 0;
6
+ exports.launchCodingAgent = exports.getCodingAgentLaunchCommands = exports.getCodingAgentLaunchCommand = exports.getRunningCodingAgents = exports.getAvailableCodingAgents = exports.discoverAvailableCodingAgents = void 0;
7
7
  const node_child_process_1 = require("node:child_process");
8
8
  const node_fs_1 = require("node:fs");
9
9
  const node_os_1 = require("node:os");
10
10
  const node_path_1 = __importDefault(require("node:path"));
11
11
  const node_util_1 = require("node:util");
12
12
  const renderer_1 = require("@remotion/renderer");
13
+ const running_processes_1 = require("./running-processes");
13
14
  const execFilePromise = (0, node_util_1.promisify)(node_child_process_1.execFile);
14
15
  const getLinuxCommandPaths = (context, command) => [
15
16
  node_path_1.default.posix.join('/usr/local/bin', command),
@@ -302,6 +303,26 @@ const getAvailableCodingAgents = () => {
302
303
  return availableCodingAgents;
303
304
  };
304
305
  exports.getAvailableCodingAgents = getAvailableCodingAgents;
306
+ const getRunningCodingAgents = async (installedCodingAgents) => {
307
+ if (installedCodingAgents.length === 0) {
308
+ return [];
309
+ }
310
+ const processes = await (0, running_processes_1.getRunningProcesses)();
311
+ if (processes === null) {
312
+ return [];
313
+ }
314
+ return installedCodingAgents
315
+ .filter((agent) => (0, running_processes_1.isAppRunning)({
316
+ processes,
317
+ executablePath: agent.applicationPath,
318
+ commands: agent.platform === 'darwin'
319
+ ? []
320
+ : codingAgentDefinitions[agent.id][agent.platform].flatMap((variant) => variant.commands),
321
+ platform: agent.platform,
322
+ }))
323
+ .map((agent) => agent.id);
324
+ };
325
+ exports.getRunningCodingAgents = getRunningCodingAgents;
305
326
  const getCodingAgentLaunchCommand = ({ codingAgent, projectPath, }) => {
306
327
  if (codingAgent.platform === 'darwin') {
307
328
  switch (codingAgent.id) {
@@ -17,3 +17,4 @@ export type EditorDiscoveryContext = {
17
17
  export declare const getDefaultEditorName: (id: "cursor" | "sublime-text" | "vscode" | "vscodium" | "webstorm" | "windsurf" | "zed") => string;
18
18
  export declare const discoverAvailableEditors: (context: EditorDiscoveryContext) => Promise<readonly InstalledEditor[]>;
19
19
  export declare const getAvailableEditors: () => Promise<readonly InstalledEditor[]>;
20
+ export declare const getRunningEditors: (installedEditors: readonly InstalledEditor[]) => Promise<readonly ("cursor" | "sublime-text" | "vscode" | "vscodium" | "webstorm" | "windsurf" | "zed")[]>;
@@ -3,13 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getAvailableEditors = exports.discoverAvailableEditors = exports.getDefaultEditorName = void 0;
6
+ exports.getRunningEditors = exports.getAvailableEditors = exports.discoverAvailableEditors = exports.getDefaultEditorName = void 0;
7
7
  const node_child_process_1 = require("node:child_process");
8
8
  const node_fs_1 = require("node:fs");
9
9
  const node_os_1 = require("node:os");
10
10
  const node_path_1 = __importDefault(require("node:path"));
11
11
  const node_util_1 = require("node:util");
12
12
  const renderer_1 = require("@remotion/renderer");
13
+ const running_processes_1 = require("./running-processes");
13
14
  const execFilePromise = (0, node_util_1.promisify)(node_child_process_1.execFile);
14
15
  const getWindowsEnvironmentPaths = (context, segments) => {
15
16
  const paths = [];
@@ -526,3 +527,25 @@ const getAvailableEditors = () => {
526
527
  return availableEditors;
527
528
  };
528
529
  exports.getAvailableEditors = getAvailableEditors;
530
+ const getRunningEditors = async (installedEditors) => {
531
+ const { platform } = process;
532
+ if (installedEditors.length === 0 ||
533
+ (platform !== 'darwin' && platform !== 'linux' && platform !== 'win32')) {
534
+ return [];
535
+ }
536
+ const processes = await (0, running_processes_1.getRunningProcesses)();
537
+ if (processes === null) {
538
+ return [];
539
+ }
540
+ return installedEditors
541
+ .filter((editor) => (0, running_processes_1.isAppRunning)({
542
+ processes,
543
+ executablePath: editor.process,
544
+ commands: editorDefinitions[editor.id][platform]
545
+ .map((variant) => 'commands' in variant ? variant.commands : [variant.command])
546
+ .flat(),
547
+ platform,
548
+ }))
549
+ .map(({ id }) => id);
550
+ };
551
+ exports.getRunningEditors = getRunningEditors;
@@ -20,5 +20,5 @@ export declare function launchEditor({ colNumber, editor, fileName, lineNumber,
20
20
  editor: ProcessAndCommand;
21
21
  vsCodeNewWindow: boolean;
22
22
  logLevel: LogLevel;
23
- }): Promise<boolean>;
23
+ }, projectFolder?: string | null): Promise<boolean>;
24
24
  export {};
@@ -1,38 +1,5 @@
1
1
  "use strict";
2
2
  // Duplicated in create-video/src/open-in-editor.ts
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
5
  };
@@ -40,27 +7,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
7
  exports.findMacOsEditorsFromProcessOutput = exports.getDisplayNameForEditor = void 0;
41
8
  exports.guessEditor = guessEditor;
42
9
  exports.launchEditor = launchEditor;
43
- const node_child_process_1 = __importStar(require("node:child_process"));
10
+ const node_child_process_1 = __importDefault(require("node:child_process"));
44
11
  const node_fs_1 = __importDefault(require("node:fs"));
45
12
  const node_os_1 = __importDefault(require("node:os"));
46
13
  const node_path_1 = __importDefault(require("node:path"));
47
- const node_util_1 = __importDefault(require("node:util"));
48
14
  const renderer_1 = require("@remotion/renderer");
49
15
  const open_in_editor_url_scheme_1 = require("./open-in-editor-url-scheme");
16
+ const running_processes_1 = require("./running-processes");
50
17
  const { Log } = renderer_1.RenderInternals;
51
- const execProm = node_util_1.default.promisify(node_child_process_1.exec);
52
18
  const isVsCodeDerivative = (editor) => {
53
- return (editor === 'code' ||
54
- editor === 'code-insiders' ||
55
- editor === 'Code.exe' ||
56
- editor === 'vscodium' ||
57
- editor === 'VSCodium.exe' ||
58
- editor === 'codium' ||
59
- editor === 'Code - Insiders.exe' ||
60
- editor === 'cursor' ||
61
- editor === 'Cursor.exe' ||
62
- editor === 'windsurf' ||
63
- editor === 'Windsurf.exe');
19
+ const editorBasename = node_path_1.default.basename(editor).replace(/\.(exe|cmd|bat)$/i, '');
20
+ return [
21
+ 'code',
22
+ 'Code',
23
+ 'code-insiders',
24
+ 'Code - Insiders',
25
+ 'vscodium',
26
+ 'VSCodium',
27
+ 'codium',
28
+ 'com.vscodium.codium',
29
+ 'com.visualstudio.code',
30
+ 'com.visualstudio.code.insiders',
31
+ 'cursor',
32
+ 'Cursor',
33
+ 'windsurf',
34
+ 'Windsurf',
35
+ ].includes(editorBasename);
64
36
  };
65
37
  function isTerminalEditor(editor) {
66
38
  switch (editor) {
@@ -257,6 +229,11 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, colNumber) {
257
229
  if (isZedEditor) {
258
230
  return ['--existing', fileName + ':' + lineNumber + ':' + colNumber];
259
231
  }
232
+ if (isVsCodeDerivative(editor)) {
233
+ return isFolder
234
+ ? [fileName]
235
+ : ['-g', fileName + ':' + lineNumber + ':' + colNumber];
236
+ }
260
237
  switch (editorBasename) {
261
238
  case 'atom':
262
239
  case 'Atom':
@@ -284,21 +261,6 @@ function getArgumentsForLineNumber(editor, fileName, lineNumber, colNumber) {
284
261
  case 'mate':
285
262
  case 'mine':
286
263
  return ['--line', lineNumber, fileName];
287
- case 'code':
288
- case 'Code':
289
- case 'code-insiders':
290
- case 'Code - Insiders':
291
- case 'vscodium':
292
- case 'VSCodium':
293
- case 'codium':
294
- case 'com.vscodium.codium':
295
- case 'com.visualstudio.code':
296
- case 'com.visualstudio.code.insiders':
297
- case 'cursor':
298
- case 'Cursor':
299
- case 'windsurf':
300
- case 'Windsurf':
301
- return ['-g', fileName + ':' + lineNumber + ':' + colNumber];
302
264
  case 'appcode':
303
265
  case 'clion':
304
266
  case 'clion64':
@@ -340,22 +302,20 @@ const findMacOsEditorsFromProcessOutput = (output) => {
340
302
  };
341
303
  exports.findMacOsEditorsFromProcessOutput = findMacOsEditorsFromProcessOutput;
342
304
  async function guessEditor() {
343
- // We can find out which editor is currently running by:
344
- // `ps x` on macOS and Linux
345
- // `Get-Process` on Windows
346
305
  const availableEditors = [];
347
- try {
306
+ const processes = await (0, running_processes_1.getRunningProcesses)();
307
+ if (processes !== null) {
348
308
  if (process.platform === 'darwin') {
349
- const output = (await execProm('ps x')).stdout.toString();
309
+ const output = processes
310
+ .map(({ executable }) => executable !== null && executable !== void 0 ? executable : '')
311
+ .join('\n');
350
312
  return (0, exports.findMacOsEditorsFromProcessOutput)(output);
351
313
  }
352
314
  if (process.platform === 'win32') {
353
- // Some processes need elevated rights to get its executable path.
354
- // Just filter them out upfront. This also saves 10-20ms on the command.
355
- const output = (await execProm('wmic process where "executablepath is not null" get executablepath')).stdout.toString();
356
- const runningProcesses = output.split('\r\n');
357
- for (let i = 0; i < runningProcesses.length; i++) {
358
- const processPath = runningProcesses[i].trim();
315
+ for (const { executable: processPath } of processes) {
316
+ if (processPath === null) {
317
+ continue;
318
+ }
359
319
  const processName = node_path_1.default.basename(processPath);
360
320
  if (COMMON_EDITORS_WIN.indexOf(processName) !== -1) {
361
321
  availableEditors.push({
@@ -367,10 +327,9 @@ async function guessEditor() {
367
327
  return availableEditors;
368
328
  }
369
329
  if (process.platform === 'linux') {
370
- // --no-heading No header line
371
- // x List all processes owned by you
372
- // -o comm Need only names column
373
- const output = (await execProm('ps x --no-heading -o comm --sort=comm')).stdout.toString();
330
+ const output = processes
331
+ .map(({ executable }) => executable !== null && executable !== void 0 ? executable : '')
332
+ .join('\n');
374
333
  const processNames = Object.keys(COMMON_EDITORS_LINUX);
375
334
  for (let i = 0; i < processNames.length; i++) {
376
335
  const processName = processNames[i];
@@ -384,9 +343,6 @@ async function guessEditor() {
384
343
  return availableEditors;
385
344
  }
386
345
  }
387
- catch (_a) {
388
- // Ignore...
389
- }
390
346
  // Last resort, use old skool env vars
391
347
  if (process.env.VISUAL) {
392
348
  return [
@@ -407,7 +363,8 @@ async function guessEditor() {
407
363
  return [];
408
364
  }
409
365
  let _childProcess = null;
410
- async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNewWindow, logLevel, }) {
366
+ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNewWindow, logLevel, }, projectFolder = null) {
367
+ var _a;
411
368
  if (!node_fs_1.default.existsSync(fileName)) {
412
369
  return false;
413
370
  }
@@ -425,6 +382,9 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
425
382
  if (editor.command.toLowerCase() === 'none') {
426
383
  return false;
427
384
  }
385
+ let folderToOpen = isVsCodeDerivative(editor.command) && !node_fs_1.default.statSync(fileName).isDirectory()
386
+ ? projectFolder
387
+ : null;
428
388
  if (process.platform === 'linux' &&
429
389
  fileName.startsWith('/mnt/') &&
430
390
  /Microsoft/i.test(node_os_1.default.release())) {
@@ -435,13 +395,16 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
435
395
  // When a Windows editor is specified, interop functionality can
436
396
  // handle the path translation, but only if a relative path is used.
437
397
  fileName = node_path_1.default.relative('', fileName);
398
+ if (folderToOpen !== null) {
399
+ folderToOpen = node_path_1.default.relative('', folderToOpen);
400
+ }
438
401
  }
439
402
  // cmd.exe on Windows is vulnerable to RCE attacks given a file name of the
440
403
  // form "C:\Users\myusername\Downloads\& curl 172.21.93.52". Use a whitelist
441
404
  // to validate user-provided file names. This doesn't cover the entire range
442
405
  // of valid file names but should cover almost all of them in practice.
443
406
  if (process.platform === 'win32' &&
444
- !WINDOWS_FILE_NAME_WHITELIST.test(fileName.trim())) {
407
+ [fileName, folderToOpen].some((target) => target !== null && !WINDOWS_FILE_NAME_WHITELIST.test(target.trim()))) {
445
408
  Log.error({ indent: false, logLevel });
446
409
  Log.error({ indent: false, logLevel }, 'Could not open ' + node_path_1.default.basename(fileName) + ' in the editor.');
447
410
  Log.error({ indent: false, logLevel });
@@ -453,7 +416,8 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
453
416
  return false;
454
417
  }
455
418
  const shouldOpenVsCodeNewWindow = isVsCodeDerivative(editor.command) && vsCodeNewWindow;
456
- if (!shouldOpenVsCodeNewWindow) {
419
+ // The file URL cannot specify both a workspace folder and a source location.
420
+ if (!shouldOpenVsCodeNewWindow && folderToOpen === null) {
457
421
  const result = (0, open_in_editor_url_scheme_1.openInEditorViaUrlScheme)({
458
422
  editor: editor.command,
459
423
  fileName,
@@ -472,6 +436,24 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
472
436
  : lineNumber
473
437
  ? getArgumentsForLineNumber(editor.command, fileName, String(lineNumber), colNumber)
474
438
  : [fileName];
439
+ if (folderToOpen !== null) {
440
+ args.unshift(folderToOpen);
441
+ }
442
+ if (process.platform === 'darwin' && folderToOpen !== null) {
443
+ const applicationPath = (_a = editor.process.match(/^(.*?\.app)\/Contents\//)) === null || _a === void 0 ? void 0 : _a[1];
444
+ if (applicationPath && node_fs_1.default.existsSync(applicationPath)) {
445
+ // Match the CLI's native macOS launch without starting its Node.js wrapper.
446
+ // -n lets Electron receive the arguments and forward them to a running instance.
447
+ const opened = await new Promise((resolve) => {
448
+ const proc = node_child_process_1.default.spawn('open', ['-n', '-g', '-a', applicationPath, '--args', ...args], { stdio: 'ignore' });
449
+ proc.on('error', () => resolve(false));
450
+ proc.on('close', (code) => resolve(code === 0));
451
+ });
452
+ if (opened) {
453
+ return true;
454
+ }
455
+ }
456
+ }
475
457
  if (_childProcess && isTerminalEditor(editor.command)) {
476
458
  // There's an existing editor process already and it's attached
477
459
  // to the terminal, so go kill it. Otherwise two separate editor
@@ -0,0 +1,12 @@
1
+ type RunningProcess = {
2
+ executable: string | null;
3
+ commandLine: string | null;
4
+ };
5
+ export declare const isAppRunning: ({ processes, executablePath, commands, platform, }: {
6
+ processes: readonly RunningProcess[];
7
+ executablePath: string;
8
+ commands: readonly string[];
9
+ platform: NodeJS.Platform;
10
+ }) => boolean;
11
+ export declare const getRunningProcesses: () => Promise<readonly RunningProcess[] | null>;
12
+ export {};
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRunningProcesses = exports.isAppRunning = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_util_1 = require("node:util");
6
+ const execFilePromise = (0, node_util_1.promisify)(node_child_process_1.execFile);
7
+ let processSnapshot = null;
8
+ const isAppRunning = ({ processes, executablePath, commands, platform, }) => {
9
+ if (platform === 'darwin') {
10
+ const applicationPath = executablePath.split('/Contents/')[0];
11
+ if (applicationPath.endsWith('.app')) {
12
+ return processes.some(({ executable }) => executable === null || executable === void 0 ? void 0 : executable.startsWith(`${applicationPath}/Contents/MacOS/`));
13
+ }
14
+ }
15
+ const escapedCommands = commands.map((command) => command.replace(/\.(exe|cmd)$/i, '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
16
+ const escapedPath = executablePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
17
+ const executablePattern = new RegExp(`^"?(?:${escapedPath}|(?:[^"\\s]*[/\\\\])?(?:${escapedCommands.join('|')})(?:\\.(?:exe|cmd|js))?)"?(?=\\s|$)`, platform === 'win32' ? 'i' : '');
18
+ return processes.some(({ executable, commandLine }) => {
19
+ // Windows terminal launches put the app after the command interpreter.
20
+ const withoutCmd = (commandLine !== null && commandLine !== void 0 ? commandLine : '').replace(/^(?:"[^"\r\n]*[/\\]cmd(?:\.exe)?"|(?:[^\s"]*[/\\])?cmd(?:\.exe)?)\s+\/[ck]\s+/i, '');
21
+ // Node-based CLIs put the script after the interpreter path.
22
+ const withoutNode = withoutCmd.replace(/^(?:"[^"\r\n]*[/\\]node(?:\.exe)?"|(?:[^\s"]*[/\\])?node(?:\.exe)?)\s+/i, '');
23
+ return (executablePattern.test(executable !== null && executable !== void 0 ? executable : '') ||
24
+ executablePattern.test(withoutNode));
25
+ });
26
+ };
27
+ exports.isAppRunning = isAppRunning;
28
+ const getRunningProcesses = () => {
29
+ if (processSnapshot !== null && processSnapshot.expiresAt > Date.now()) {
30
+ return processSnapshot.promise;
31
+ }
32
+ const snapshot = {
33
+ expiresAt: Infinity,
34
+ promise: (async () => {
35
+ try {
36
+ if (process.platform === 'win32') {
37
+ const { stdout } = await execFilePromise('powershell.exe', [
38
+ '-NoProfile',
39
+ '-NonInteractive',
40
+ '-Command',
41
+ 'ConvertTo-Json -Compress -InputObject @(Get-CimInstance Win32_Process | Select-Object ExecutablePath, CommandLine)',
42
+ ], { timeout: 5000 });
43
+ const processes = JSON.parse(stdout);
44
+ return processes.map(({ ExecutablePath, CommandLine }) => ({
45
+ executable: ExecutablePath,
46
+ commandLine: CommandLine,
47
+ }));
48
+ }
49
+ if (process.platform === 'darwin') {
50
+ const { stdout } = await execFilePromise('ps', ['-ax', '-o', 'comm='], {
51
+ timeout: 5000,
52
+ });
53
+ return stdout
54
+ .split('\n')
55
+ .filter(Boolean)
56
+ .map((line) => ({
57
+ executable: line.trim(),
58
+ commandLine: null,
59
+ }));
60
+ }
61
+ if (process.platform === 'linux') {
62
+ // Use a fixed-width name column to preserve spaces in both fields.
63
+ const executableWidth = 64;
64
+ const { stdout } = await execFilePromise('ps', ['-e', '-ww', '-o', `comm:${executableWidth}=`, '-o', 'args='], { timeout: 5000 });
65
+ return stdout
66
+ .split('\n')
67
+ .filter(Boolean)
68
+ .map((line) => ({
69
+ executable: line.slice(0, executableWidth).trim(),
70
+ commandLine: line.slice(executableWidth).trim(),
71
+ }));
72
+ }
73
+ }
74
+ catch (_a) {
75
+ return null;
76
+ }
77
+ return null;
78
+ })(),
79
+ };
80
+ processSnapshot = snapshot;
81
+ // Share the in-flight query and its result across nearby editor and agent
82
+ // requests, but refresh it when Studio is revisited later.
83
+ snapshot.promise.then(() => {
84
+ snapshot.expiresAt = Date.now() + 1000;
85
+ });
86
+ return snapshot.promise;
87
+ };
88
+ exports.getRunningProcesses = getRunningProcesses;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.updateVideoConfigNumericExpression = exports.parseVideoConfigNumericExpression = void 0;
37
37
  const recast = __importStar(require("recast"));
38
+ const no_react_1 = require("remotion/no-react");
38
39
  const b = recast.types.builders;
39
40
  const getNumericLiteral = (node) => {
40
41
  if (node.type === 'NumericLiteral') {
@@ -61,11 +62,13 @@ const getVideoConfigValue = ({ node, videoConfigValues, }) => {
61
62
  if (node.type !== 'Identifier') {
62
63
  return null;
63
64
  }
64
- const value = videoConfigValues[node.name];
65
- if (value === undefined || !Number.isFinite(value)) {
65
+ const binding = videoConfigValues instanceof Map
66
+ ? videoConfigValues.get(node)
67
+ : videoConfigValues[node.name];
68
+ if (binding === undefined) {
66
69
  return null;
67
70
  }
68
- return { identifier: node.name, value };
71
+ return { identifier: node.name, binding };
69
72
  };
70
73
  const parseVideoConfigNumericExpression = ({ node, videoConfigValues, }) => {
71
74
  if (node.type === 'TSAsExpression') {
@@ -96,16 +99,11 @@ const parseVideoConfigNumericExpression = ({ node, videoConfigValues, }) => {
96
99
  if (minuend === null || subtrahend === null) {
97
100
  return null;
98
101
  }
99
- const resolvedValue = minuend.value - subtrahend;
100
- if (!Number.isFinite(resolvedValue)) {
101
- return null;
102
- }
103
102
  return {
104
103
  type: 'video-config-subtraction',
105
104
  identifier: minuend.identifier,
106
- minuend: minuend.value,
105
+ binding: minuend.binding,
107
106
  subtrahend,
108
- value: resolvedValue,
109
107
  };
110
108
  }
111
109
  if (node.operator !== '*') {
@@ -131,17 +129,12 @@ const parseVideoConfigNumericExpression = ({ node, videoConfigValues, }) => {
131
129
  }
132
130
  const multiplier = factorPosition === 'left' ? leftNumber : rightNumber;
133
131
  const configValue = factorPosition === 'left' ? rightVideoConfig : leftVideoConfig;
134
- const value = multiplier * configValue.value;
135
- if (!Number.isFinite(value)) {
136
- return null;
137
- }
138
132
  return {
139
133
  type: 'video-config-multiplication',
140
134
  identifier: configValue.identifier,
141
135
  multiplier,
142
- multiplicand: configValue.value,
136
+ binding: configValue.binding,
143
137
  factorPosition,
144
- value,
145
138
  };
146
139
  };
147
140
  exports.parseVideoConfigNumericExpression = parseVideoConfigNumericExpression;
@@ -156,13 +149,21 @@ const updateVideoConfigNumericExpression = ({ expression, value, }) => {
156
149
  return numericExpression(value);
157
150
  }
158
151
  if (expression.type === 'video-config-value') {
159
- return value === expression.value
152
+ return value ===
153
+ no_react_1.NoReactInternals.evaluateSourceNumericValue(expression, null)
160
154
  ? b.identifier(expression.identifier)
161
155
  : numericExpression(value);
162
156
  }
163
157
  if (expression.type === 'video-config-subtraction') {
164
- const subtrahend = expression.minuend - value;
165
- if (!Number.isFinite(subtrahend)) {
158
+ const subtrahend = (expression.binding.type === 'constant'
159
+ ? expression.binding.value
160
+ : NaN) - value;
161
+ if (!Number.isFinite(subtrahend) ||
162
+ (expression.binding.type === 'constant'
163
+ ? expression.binding.value
164
+ : NaN) -
165
+ subtrahend !==
166
+ value) {
166
167
  return numericExpression(value);
167
168
  }
168
169
  return b.binaryExpression('-', b.identifier(expression.identifier), numericExpression(subtrahend));
@@ -170,8 +171,16 @@ const updateVideoConfigNumericExpression = ({ expression, value, }) => {
170
171
  if (expression.type !== 'video-config-multiplication' || value === 0) {
171
172
  return numericExpression(value);
172
173
  }
173
- const multiplier = value / expression.multiplicand;
174
- if (!Number.isFinite(multiplier) || multiplier === 0) {
174
+ const multiplier = value /
175
+ (expression.binding.type === 'constant' ? expression.binding.value : NaN);
176
+ // Preserve the expression only if evaluating it reproduces the requested value.
177
+ if (!Number.isFinite(multiplier) ||
178
+ multiplier === 0 ||
179
+ multiplier *
180
+ (expression.binding.type === 'constant'
181
+ ? expression.binding.value
182
+ : NaN) !==
183
+ value) {
175
184
  return numericExpression(value);
176
185
  }
177
186
  const factor = numericExpression(multiplier);
@@ -1,6 +1,9 @@
1
- import type { File } from '@babel/types';
2
- import type { VideoConfigValues } from 'remotion';
3
- export type VideoConfigIdentifierValues = Record<string, number>;
1
+ import type { File, Identifier } from '@babel/types';
2
+ import type { VideoConfigNumericBinding, VideoConfigValues } from 'remotion';
3
+ export type VideoConfigIdentifierValues = Map<Identifier, VideoConfigNumericBinding> | Record<string, VideoConfigNumericBinding>;
4
+ export declare const getVideoConfigIdentifiers: ({ ast, }: {
5
+ ast: File;
6
+ }) => Map<Identifier, VideoConfigNumericBinding>;
4
7
  export declare const getVideoConfigIdentifierValues: ({ ast, videoConfigValues, }: {
5
8
  ast: File;
6
9
  videoConfigValues: VideoConfigValues | null;