@remotion/studio-server 4.0.533 → 4.0.535

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 (68) 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/file-watcher.js +2 -0
  4. package/dist/helpers/app-discovery.d.ts +9 -0
  5. package/dist/helpers/app-discovery.js +61 -0
  6. package/dist/helpers/coding-agent-registry.d.ts +1 -0
  7. package/dist/helpers/coding-agent-registry.js +22 -1
  8. package/dist/helpers/editor-registry.d.ts +1 -0
  9. package/dist/helpers/editor-registry.js +24 -1
  10. package/dist/helpers/open-in-app.d.ts +13 -0
  11. package/dist/helpers/open-in-app.js +72 -0
  12. package/dist/helpers/open-in-editor.d.ts +1 -1
  13. package/dist/helpers/open-in-editor.js +67 -84
  14. package/dist/helpers/recently-used-apps.d.ts +9 -0
  15. package/dist/helpers/recently-used-apps.js +63 -0
  16. package/dist/helpers/running-processes.d.ts +12 -0
  17. package/dist/helpers/running-processes.js +88 -0
  18. package/dist/helpers/video-config-numeric-expression.js +29 -20
  19. package/dist/helpers/video-config-values.d.ts +6 -3
  20. package/dist/helpers/video-config-values.js +42 -26
  21. package/dist/preview-server/api-routes.js +8 -5
  22. package/dist/preview-server/live-events.d.ts +1 -0
  23. package/dist/preview-server/live-events.js +12 -1
  24. package/dist/preview-server/routes/add-sequence-keyframe.js +0 -1
  25. package/dist/preview-server/routes/app-info.d.ts +3 -0
  26. package/dist/preview-server/routes/app-info.js +16 -0
  27. package/dist/preview-server/routes/can-update-effect-props.d.ts +4 -6
  28. package/dist/preview-server/routes/can-update-effect-props.js +5 -28
  29. package/dist/preview-server/routes/can-update-sequence-props.d.ts +6 -8
  30. package/dist/preview-server/routes/can-update-sequence-props.js +11 -12
  31. package/dist/preview-server/routes/default-coding-agent.d.ts +1 -2
  32. package/dist/preview-server/routes/default-coding-agent.js +11 -19
  33. package/dist/preview-server/routes/default-editor.js +9 -29
  34. package/dist/preview-server/routes/delete-keyframes.d.ts +2 -2
  35. package/dist/preview-server/routes/delete-keyframes.js +0 -1
  36. package/dist/preview-server/routes/element-install-plan.js +5 -0
  37. package/dist/preview-server/routes/insert-basic-captions.js +1 -0
  38. package/dist/preview-server/routes/insert-element.js +63 -20
  39. package/dist/preview-server/routes/install-remotion-skill.d.ts +2 -1
  40. package/dist/preview-server/routes/install-remotion-skill.js +87 -56
  41. package/dist/preview-server/routes/open-in-editor.d.ts +1 -1
  42. package/dist/preview-server/routes/open-in-editor.js +2 -56
  43. package/dist/preview-server/routes/redo.js +2 -1
  44. package/dist/preview-server/routes/remotion-skills-info.d.ts +2 -1
  45. package/dist/preview-server/routes/remotion-skills-info.js +57 -3
  46. package/dist/preview-server/routes/save-sequence-props.js +0 -1
  47. package/dist/preview-server/routes/shared-memory-capture-support.d.ts +3 -0
  48. package/dist/preview-server/routes/shared-memory-capture-support.js +13 -0
  49. package/dist/preview-server/routes/source-file-write-queue.d.ts +1 -1
  50. package/dist/preview-server/routes/subscribe-to-sequence-props.js +1 -2
  51. package/dist/preview-server/routes/undo.js +2 -1
  52. package/dist/preview-server/routes/unsubscribe-from-sequence-props.js +0 -1
  53. package/dist/preview-server/routes/update-config.js +12 -5
  54. package/dist/preview-server/routes/update-sequence-keyframe-settings.js +0 -1
  55. package/dist/preview-server/routes/wrap-node.js +13 -4
  56. package/dist/preview-server/sequence-props-watchers.d.ts +3 -5
  57. package/dist/preview-server/sequence-props-watchers.js +9 -17
  58. package/dist/preview-server/studio-protocol/handle-element-library.js +14 -0
  59. package/dist/preview-server/studio-protocol/handle-install.js +2 -1
  60. package/dist/preview-server/undo-stack.js +1 -0
  61. package/dist/preview-server/update-available.js +17 -0
  62. package/dist/preview-server/watch-ignore-next-change.d.ts +1 -0
  63. package/dist/preview-server/watch-ignore-next-change.js +15 -2
  64. package/dist/routes.js +3 -1
  65. package/dist/start-studio.js +13 -6
  66. package/dist/studio-shortcuts.d.ts +13 -0
  67. package/dist/studio-shortcuts.js +257 -0
  68. 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 };
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.writeFileAndNotifyFileWatchers = exports.installFileWatcher = exports.getFileWatcherRegistry = exports.setFileWatcherRegistry = exports.createFileWatcherRegistry = void 0;
37
37
  const node_fs_1 = __importStar(require("node:fs"));
38
+ const watch_ignore_next_change_1 = require("./preview-server/watch-ignore-next-change");
38
39
  const getRegistryKey = (file, existenceOnly) => existenceOnly ? `${file}\0existence-only` : file;
39
40
  const createFileWatcherRegistry = () => {
40
41
  const sharedWatchers = new Map();
@@ -130,6 +131,7 @@ const createFileWatcherRegistry = () => {
130
131
  };
131
132
  const _writeFileAndNotifyFileWatchers = ({ file, content, originatorClientId, metadata, }) => {
132
133
  var _a;
134
+ (0, watch_ignore_next_change_1.prepareBundlerForFileWrite)(file);
133
135
  (0, node_fs_1.writeFileSync)(file, content);
134
136
  const shared = sharedWatchers.get(getRegistryKey(file, false));
135
137
  if (!shared) {
@@ -0,0 +1,9 @@
1
+ import type { DefaultEditor } from '@remotion/renderer';
2
+ import type { GetDefaultEditorInfoResponse } from '@remotion/studio-shared';
3
+ export declare const getAppDiscovery: () => Promise<{
4
+ installedEditors: readonly import("./editor-registry").InstalledEditor[];
5
+ installedCodingAgents: readonly import("./coding-agent-registry").InstalledCodingAgent[];
6
+ runningEditors: readonly ("cursor" | "sublime-text" | "vscode" | "vscodium" | "webstorm" | "windsurf" | "zed")[];
7
+ runningCodingAgents: readonly ("claude-code" | "codex" | "copilot" | "cursor")[];
8
+ }>;
9
+ export declare const getEditorInfo: (configuredEditor: DefaultEditor | null) => Promise<GetDefaultEditorInfoResponse>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEditorInfo = exports.getAppDiscovery = void 0;
4
+ const coding_agent_registry_1 = require("./coding-agent-registry");
5
+ const custom_editor_1 = require("./custom-editor");
6
+ const editor_registry_1 = require("./editor-registry");
7
+ let appDiscovery = null;
8
+ const discoverApps = async () => {
9
+ const [installedEditors, installedCodingAgents] = await Promise.all([
10
+ (0, editor_registry_1.getAvailableEditors)(),
11
+ (0, coding_agent_registry_1.getAvailableCodingAgents)(),
12
+ ]);
13
+ const [runningEditors, runningCodingAgents] = await Promise.all([
14
+ (0, editor_registry_1.getRunningEditors)(installedEditors),
15
+ (0, coding_agent_registry_1.getRunningCodingAgents)(installedCodingAgents),
16
+ ]);
17
+ return {
18
+ installedEditors,
19
+ installedCodingAgents,
20
+ runningEditors,
21
+ runningCodingAgents,
22
+ };
23
+ };
24
+ // The terminal helper and Studio requests share the same in-flight discovery
25
+ // and process snapshot. Configuration and app history are read separately.
26
+ const getAppDiscovery = () => {
27
+ appDiscovery !== null && appDiscovery !== void 0 ? appDiscovery : (appDiscovery = discoverApps());
28
+ return appDiscovery;
29
+ };
30
+ exports.getAppDiscovery = getAppDiscovery;
31
+ const getEditorInfo = async (configuredEditor) => {
32
+ const { installedEditors, runningEditors } = await (0, exports.getAppDiscovery)();
33
+ const customEditor = configuredEditor &&
34
+ typeof configuredEditor === 'object' &&
35
+ (0, custom_editor_1.resolveCustomEditorExecutable)(configuredEditor)
36
+ ? configuredEditor
37
+ : null;
38
+ return {
39
+ defaultEditor: configuredEditor && typeof configuredEditor === 'object'
40
+ ? 'custom'
41
+ : configuredEditor,
42
+ runningEditors,
43
+ installedEditors: [
44
+ ...installedEditors.map(({ id, name, nameWithType }) => ({
45
+ id,
46
+ name,
47
+ nameWithType,
48
+ })),
49
+ ...(customEditor
50
+ ? [
51
+ {
52
+ id: 'custom',
53
+ name: customEditor.name,
54
+ nameWithType: customEditor.name,
55
+ },
56
+ ]
57
+ : []),
58
+ ],
59
+ };
60
+ };
61
+ exports.getEditorInfo = getEditorInfo;
@@ -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;
@@ -0,0 +1,13 @@
1
+ import { type DefaultEditor } from '@remotion/renderer';
2
+ import type { OpenInCodingAgentRequest, OpenInCodingAgentResponse, OpenInEditorRequest, OpenInEditorResponse } from '@remotion/studio-shared';
3
+ export declare const openInEditor: ({ input, remotionRoot, logLevel, getDefaultEditor, }: {
4
+ input: OpenInEditorRequest;
5
+ remotionRoot: string;
6
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
7
+ getDefaultEditor: () => DefaultEditor | null;
8
+ }) => Promise<OpenInEditorResponse>;
9
+ export declare const openInCodingAgent: ({ input, logLevel, remotionRoot, }: {
10
+ input: OpenInCodingAgentRequest;
11
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
12
+ remotionRoot: string;
13
+ }) => Promise<OpenInCodingAgentResponse>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.openInCodingAgent = exports.openInEditor = void 0;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const renderer_1 = require("@remotion/renderer");
9
+ const coding_agent_registry_1 = require("./coding-agent-registry");
10
+ const custom_editor_1 = require("./custom-editor");
11
+ const open_in_editor_1 = require("./open-in-editor");
12
+ const resolve_editor_1 = require("./resolve-editor");
13
+ const openInEditor = async ({ input, remotionRoot, logLevel, getDefaultEditor, }) => {
14
+ try {
15
+ if (!('stack' in input)) {
16
+ throw new TypeError('Need to pass stack');
17
+ }
18
+ const { stack } = input;
19
+ if (input.editorId !== null &&
20
+ input.editorId !== 'custom' &&
21
+ !renderer_1.defaultEditorIds.includes(input.editorId)) {
22
+ return { success: false };
23
+ }
24
+ const editor = await (0, resolve_editor_1.resolveEditor)({
25
+ defaultEditor: getDefaultEditor(),
26
+ logLevel,
27
+ preferredEditor: input.editorId,
28
+ });
29
+ if (!editor) {
30
+ return { success: false };
31
+ }
32
+ const fileName = node_path_1.default.resolve(remotionRoot, stack.originalFileName);
33
+ const didOpen = editor.type === 'custom'
34
+ ? await (0, custom_editor_1.launchCustomEditor)({
35
+ editor: editor.editor,
36
+ resolvedExecutable: editor,
37
+ targetPath: fileName,
38
+ lineNumber: stack.originalLineNumber,
39
+ columnNumber: stack.originalColumnNumber,
40
+ logLevel,
41
+ spawnProcess: null,
42
+ })
43
+ : await (0, open_in_editor_1.launchEditor)({
44
+ colNumber: stack.originalColumnNumber,
45
+ editor,
46
+ fileName,
47
+ lineNumber: stack.originalLineNumber,
48
+ vsCodeNewWindow: false,
49
+ logLevel,
50
+ }, remotionRoot);
51
+ return { success: didOpen };
52
+ }
53
+ catch (_a) {
54
+ return { success: false };
55
+ }
56
+ };
57
+ exports.openInEditor = openInEditor;
58
+ const openInCodingAgent = async ({ input, logLevel, remotionRoot, }) => {
59
+ const codingAgent = (await (0, coding_agent_registry_1.getAvailableCodingAgents)()).find((agent) => agent.id === input.codingAgentId);
60
+ if (!codingAgent) {
61
+ return { success: false };
62
+ }
63
+ return {
64
+ success: await (0, coding_agent_registry_1.launchCodingAgent)({
65
+ codingAgent,
66
+ projectPath: remotionRoot,
67
+ logLevel,
68
+ prompt: input.prompt,
69
+ }),
70
+ };
71
+ };
72
+ exports.openInCodingAgent = openInCodingAgent;
@@ -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,8 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
425
382
  if (editor.command.toLowerCase() === 'none') {
426
383
  return false;
427
384
  }
385
+ const isDirectory = node_fs_1.default.statSync(fileName).isDirectory();
386
+ let folderToOpen = isVsCodeDerivative(editor.command) && !isDirectory ? projectFolder : null;
428
387
  if (process.platform === 'linux' &&
429
388
  fileName.startsWith('/mnt/') &&
430
389
  /Microsoft/i.test(node_os_1.default.release())) {
@@ -435,13 +394,16 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
435
394
  // When a Windows editor is specified, interop functionality can
436
395
  // handle the path translation, but only if a relative path is used.
437
396
  fileName = node_path_1.default.relative('', fileName);
397
+ if (folderToOpen !== null) {
398
+ folderToOpen = node_path_1.default.relative('', folderToOpen);
399
+ }
438
400
  }
439
401
  // cmd.exe on Windows is vulnerable to RCE attacks given a file name of the
440
402
  // form "C:\Users\myusername\Downloads\& curl 172.21.93.52". Use a whitelist
441
403
  // to validate user-provided file names. This doesn't cover the entire range
442
404
  // of valid file names but should cover almost all of them in practice.
443
405
  if (process.platform === 'win32' &&
444
- !WINDOWS_FILE_NAME_WHITELIST.test(fileName.trim())) {
406
+ [fileName, folderToOpen].some((target) => target !== null && !WINDOWS_FILE_NAME_WHITELIST.test(target.trim()))) {
445
407
  Log.error({ indent: false, logLevel });
446
408
  Log.error({ indent: false, logLevel }, 'Could not open ' + node_path_1.default.basename(fileName) + ' in the editor.');
447
409
  Log.error({ indent: false, logLevel });
@@ -453,7 +415,8 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
453
415
  return false;
454
416
  }
455
417
  const shouldOpenVsCodeNewWindow = isVsCodeDerivative(editor.command) && vsCodeNewWindow;
456
- if (!shouldOpenVsCodeNewWindow) {
418
+ // The file URL cannot specify both a workspace folder and a source location.
419
+ if (!shouldOpenVsCodeNewWindow && folderToOpen === null && !isDirectory) {
457
420
  const result = (0, open_in_editor_url_scheme_1.openInEditorViaUrlScheme)({
458
421
  editor: editor.command,
459
422
  fileName,
@@ -469,9 +432,29 @@ async function launchEditor({ colNumber, editor, fileName, lineNumber, vsCodeNew
469
432
  }
470
433
  const args = shouldOpenVsCodeNewWindow
471
434
  ? ['--new-window', fileName]
472
- : lineNumber
435
+ : lineNumber && !isDirectory
473
436
  ? getArgumentsForLineNumber(editor.command, fileName, String(lineNumber), colNumber)
474
437
  : [fileName];
438
+ if (folderToOpen !== null) {
439
+ args.unshift(folderToOpen);
440
+ }
441
+ if (process.platform === 'darwin' &&
442
+ isVsCodeDerivative(editor.command) &&
443
+ (folderToOpen !== null || isDirectory)) {
444
+ const applicationPath = (_a = editor.process.match(/^(.*?\.app)\/Contents\//)) === null || _a === void 0 ? void 0 : _a[1];
445
+ if (applicationPath && node_fs_1.default.existsSync(applicationPath)) {
446
+ // Match the CLI's native macOS launch without starting its Node.js wrapper.
447
+ // -n lets Electron receive the arguments and forward them to a running instance.
448
+ const opened = await new Promise((resolve) => {
449
+ const proc = node_child_process_1.default.spawn('open', ['-n', '-g', '-a', applicationPath, '--args', ...args], { stdio: 'ignore' });
450
+ proc.on('error', () => resolve(false));
451
+ proc.on('close', (code) => resolve(code === 0));
452
+ });
453
+ if (opened) {
454
+ return true;
455
+ }
456
+ }
457
+ }
475
458
  if (_childProcess && isTerminalEditor(editor.command)) {
476
459
  // There's an existing editor process already and it's attached
477
460
  // to the terminal, so go kill it. Otherwise two separate editor
@@ -0,0 +1,9 @@
1
+ export declare const subscribeToRecentlyUsedApps: ({ remotionRoot, onChange, }: {
2
+ remotionRoot: string;
3
+ onChange: () => void;
4
+ }) => () => void;
5
+ export declare const getRecentlyUsedApps: ({ remotionRoot, type, recentlyUsedIds, }: {
6
+ remotionRoot: string;
7
+ type: "coding-agent" | "editor";
8
+ recentlyUsedIds: readonly string[] | null;
9
+ }) => Promise<readonly string[]>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getRecentlyUsedApps = exports.subscribeToRecentlyUsedApps = void 0;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const renderer_1 = require("@remotion/renderer");
10
+ const histories = new Map();
11
+ const historyListeners = new Set();
12
+ const subscribeToRecentlyUsedApps = ({ remotionRoot, onChange, }) => {
13
+ const listener = { remotionRoot, onChange };
14
+ historyListeners.add(listener);
15
+ return () => {
16
+ historyListeners.delete(listener);
17
+ };
18
+ };
19
+ exports.subscribeToRecentlyUsedApps = subscribeToRecentlyUsedApps;
20
+ const getRecentlyUsedApps = ({ remotionRoot, type, recentlyUsedIds, }) => {
21
+ var _a;
22
+ const filePath = node_path_1.default.join(remotionRoot, 'node_modules', '.cache', 'remotion', `recently-used-${type}s.json`);
23
+ const allowedIds = type === 'editor' ? [...renderer_1.defaultEditorIds, 'custom'] : renderer_1.defaultCodingAgentIds;
24
+ const previous = (_a = histories.get(filePath)) !== null && _a !== void 0 ? _a : (async () => {
25
+ try {
26
+ const stored = JSON.parse(await (0, promises_1.readFile)(filePath, 'utf8'));
27
+ return Array.isArray(stored)
28
+ ? [
29
+ ...new Set(stored.filter((id) => allowedIds.includes(id))),
30
+ ]
31
+ : [];
32
+ }
33
+ catch (_a) {
34
+ return [];
35
+ }
36
+ })();
37
+ const history = previous.then(async (ids) => {
38
+ if (recentlyUsedIds === null) {
39
+ return ids;
40
+ }
41
+ const updatedIds = [
42
+ ...new Set(recentlyUsedIds.filter((id) => allowedIds.includes(id))),
43
+ ];
44
+ if (JSON.stringify(ids) !== JSON.stringify(updatedIds)) {
45
+ try {
46
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(filePath), { recursive: true });
47
+ await (0, promises_1.writeFile)(filePath, JSON.stringify(updatedIds));
48
+ }
49
+ catch (_a) {
50
+ // Keep the history in memory when the project cache is not writable.
51
+ }
52
+ historyListeners.forEach((listener) => {
53
+ if (listener.remotionRoot === remotionRoot) {
54
+ listener.onChange();
55
+ }
56
+ });
57
+ }
58
+ return updatedIds;
59
+ });
60
+ histories.set(filePath, history);
61
+ return history;
62
+ };
63
+ exports.getRecentlyUsedApps = getRecentlyUsedApps;
@@ -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 {};