auto-terminal-profile 5.0.0 → 8.1.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.
Files changed (50) hide show
  1. package/license.txt +2 -2
  2. package/package.json +45 -21
  3. package/readme.md +72 -31
  4. package/source/cli/actions/config/index.js +3 -0
  5. package/source/cli/actions/config/set-mode.js +24 -0
  6. package/source/cli/actions/config/set.js +44 -0
  7. package/source/cli/actions/config/show.js +23 -0
  8. package/source/cli/actions/index.js +3 -0
  9. package/source/cli/actions/update.js +17 -0
  10. package/source/cli/actions/watch.js +13 -0
  11. package/source/cli/commands/config/config.js +8 -0
  12. package/source/cli/commands/config/index.js +1 -0
  13. package/source/cli/commands/config/set-mode.js +24 -0
  14. package/source/cli/commands/config/set.js +15 -0
  15. package/source/cli/commands/config/show.js +6 -0
  16. package/source/cli/commands/index.js +3 -0
  17. package/source/cli/commands/update.js +11 -0
  18. package/source/cli/commands/watch.js +6 -0
  19. package/source/cli.js +17 -0
  20. package/source/library/get-config.js +32 -0
  21. package/source/library/get-current-mode.js +10 -0
  22. package/source/library/index.js +3 -0
  23. package/source/library/modes.js +3 -0
  24. package/.github/funding.yml +0 -1
  25. package/actions/disable.js +0 -7
  26. package/actions/enable.js +0 -58
  27. package/actions/index.js +0 -5
  28. package/actions/set-mode-profile.js +0 -21
  29. package/actions/status.js +0 -12
  30. package/actions/update-profile.js +0 -26
  31. package/changelog.md +0 -84
  32. package/cli.js +0 -60
  33. package/config.js +0 -43
  34. package/constants/index.js +0 -2
  35. package/constants/launch-agent-plist-file-path.js +0 -5
  36. package/constants/package-json.js +0 -5
  37. package/dark-mode-notify/LICENSE +0 -21
  38. package/dark-mode-notify/Makefile +0 -17
  39. package/dark-mode-notify/Package.swift +0 -15
  40. package/dark-mode-notify/README.md +0 -48
  41. package/dark-mode-notify/main.swift +0 -42
  42. package/functions/disable-automatic-switching.js +0 -9
  43. package/functions/enable-automatic-switching.js +0 -13
  44. package/functions/get-current-mode.js +0 -8
  45. package/functions/get-launch-agent-plist-file-contents.js +0 -27
  46. package/functions/index.js +0 -7
  47. package/functions/is-automatic-switching-enabled.js +0 -32
  48. package/functions/is-terminal-open.js +0 -18
  49. package/functions/set-terminal-profile.js +0 -11
  50. package/templates/launch-agent.xml +0 -31
package/license.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Patrik Csak
3
+ Copyright (c) Patrik Csak <p@trikcsak.com> [https://patrikcsak.com]
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-terminal-profile",
3
- "version": "5.0.0",
3
+ "version": "8.1.0",
4
4
  "description": "Automatically switch macOS Terminal profile when system dark / light mode changes",
5
5
  "keywords": [
6
6
  "macos",
@@ -9,37 +9,61 @@
9
9
  "dark mode",
10
10
  "profile"
11
11
  ],
12
- "repository": "github:patrik-csak/auto-terminal-profile",
13
- "funding": "https://buymeacoffee.com/patrikcsak",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/patrik-csak/auto-terminal-profile.git"
15
+ },
14
16
  "license": "MIT",
15
17
  "author": "Patrik Csak <p@trikcsak.com> (https://patrikcsak.com)",
16
18
  "type": "module",
17
- "bin": "./cli.js",
19
+ "imports": {
20
+ "#*": "./source/*/index.js",
21
+ "#package-json": "./package.json"
22
+ },
23
+ "bin": {
24
+ "auto-terminal-profile": "source/cli.js"
25
+ },
26
+ "files": [
27
+ "source"
28
+ ],
18
29
  "scripts": {
19
- "format": "xo --fix && sort-package-json",
20
- "postinstall": "cd dark-mode-notify && make build",
21
- "test": "xo && sort-package-json --check"
30
+ "lint:check": "eslint",
31
+ "lint:fix": "eslint --fix",
32
+ "quality:check": "npm run lint:check && npm run unused:check",
33
+ "quality:fix": "npm run lint:fix",
34
+ "test": "node --experimental-test-module-mocks --test",
35
+ "test:coverage": "npm run test -- --experimental-test-coverage",
36
+ "unused:check": "knip"
22
37
  },
23
38
  "dependencies": {
24
- "commander": "^12.0.0",
25
- "conf": "^13.0.1",
26
- "dark-mode": "^4.0.0",
27
- "env-paths": "^3.0.0",
28
- "execa": "^9.5.1",
29
- "pupa": "^3.1.0",
30
- "read-package-up": "^11.0.0",
31
- "run-applescript": "^7.0.0",
32
- "terminal-profile": "^2.0.0",
33
- "untildify": "^5.0.0"
39
+ "commander": "^15.0.0",
40
+ "conf": "^15.0.2",
41
+ "consola": "^3.4.2",
42
+ "dark-mode": "^5.0.0",
43
+ "mac-terminal": "^6.1.0"
34
44
  },
35
45
  "devDependencies": {
36
- "sort-package-json": "^2.7.0",
37
- "xo": "^0.59.3"
46
+ "eslint": "^10.0.3",
47
+ "eslint-plugin-package-json": "^1.4.0",
48
+ "knip": "^6.3.1",
49
+ "xo": "^3.0.2"
38
50
  },
39
51
  "engines": {
40
- "node": ">=18 <=20"
52
+ "node": ">=22 <=24"
53
+ },
54
+ "devEngines": {
55
+ "runtime": {
56
+ "name": "node"
57
+ },
58
+ "packageManager": {
59
+ "name": "npm",
60
+ "version": "^11.16"
61
+ }
41
62
  },
42
63
  "os": [
43
64
  "darwin"
44
- ]
65
+ ],
66
+ "allowScripts": {
67
+ "unrs-resolver": false
68
+ }
45
69
  }
package/readme.md CHANGED
@@ -1,51 +1,92 @@
1
- # Auto Terminal Profile
1
+ # auto-terminal-profile
2
2
 
3
- Automatically switch [macOS Terminal](https://en.wikipedia.org/wiki/Terminal_%28macOS%29) profiles when the [dark / light appearance mode](https://support.apple.com/guide/mac-help/use-a-light-or-dark-appearance-mchl52e1c2d2/mac) changes
3
+ Automatically switch [Terminal](https://en.wikipedia.org/wiki/Terminal_%28macOS%29) profiles when macOS [dark/light mode](https://support.apple.com/guide/mac-help/use-a-light-or-dark-appearance-mchl52e1c2d2/mac) changes
4
4
 
5
5
  ![auto-terminal-profile demonstration screen recording](./documentation/demo.gif)
6
6
 
7
- ## Prerequisites
7
+ ## Usage
8
8
 
9
- - [Node.js](https://nodejs.org/) 18–20
9
+ - [Homebrew](#homebrew) · **recommended**
10
+ - [npm](#npm)
10
11
 
11
- ## Installation
12
+ ### Homebrew
12
13
 
13
- ```shell
14
- npm install --global auto-terminal-profile
15
- ```
14
+ The easiest way to use auto-terminal-profile is to install the [`auto-terminal-profile` Homebrew formula](https://github.com/patrik-csak/homebrew-tap/blob/main/Formula/auto-terminal-profile.rb) and run it as a [Homebrew](https://brew.sh) [service](https://docs.brew.sh/Manpage#services-subcommand):
16
15
 
17
- ## Usage
16
+ 1. Install
17
+
18
+ ```shell
19
+ brew install patrik-csak/tap/auto-terminal-profile
20
+ ```
21
+
22
+ 1. [Import the Terminal profiles](https://support.apple.com/guide/terminal/import-and-export-terminal-profiles-trml4299c696/mac) you want to use if you haven’t already
23
+
24
+ 1. Set your preferred dark and light mode profiles:
25
+
26
+ ```shell
27
+ auto-terminal-profile config set
28
+ ```
29
+
30
+ <details>
31
+ <summary><small>Or set profiles individually</small></summary>
32
+
33
+ ```shell
34
+ auto-terminal-profile config set dark 'Clear Dark'
35
+ auto-terminal-profile config set light 'Clear Light'
36
+ ```
37
+ </details>
38
+
39
+ 1. Enable automatic switching
40
+
41
+ ```shell
42
+ brew services start auto-terminal-profile
43
+ ```
44
+
45
+ The process will run as a macOS launchd agent, and will start automatically on login
46
+
47
+ <details>
48
+ <summary><small>Disable automatic switching</small></summary>
49
+
50
+ ```shell
51
+ brew services stop auto-terminal-profile
52
+ ```
53
+ </details>
54
+
55
+ ### npm
56
+
57
+ You can use the [`auto-terminal-profile` npm package](https://npmx.dev/package/auto-terminal-profile) directly, but it doesn’t have built-in background service management
18
58
 
19
- ### Enable automatic profile switching
59
+ 1. Install
20
60
 
21
- To get started, enable automatic profile switching and set your preferred dark and light mode profiles:
61
+ ```shell
62
+ npm install --global auto-terminal-profile
63
+ ```
22
64
 
23
- ```shell
24
- auto-terminal-profile enable \
25
- --dark-profile='One Dark' \
26
- --light-profile='One Light'
27
- ```
65
+ 1. Set your preferred dark and light mode profiles:
28
66
 
29
- ### Switch profile on Terminal startup
67
+ ```shell
68
+ auto-terminal-profile config set
69
+ ```
30
70
 
31
- Auto Terminal Profile only runs if Terminal is running, so the profile can fall out of sync if the macOS appearance mode changes while Terminal isn&rsquo;t running.
71
+ <details>
72
+ <summary><small>Or set profiles individually</small></summary>
32
73
 
33
- To sync the Terminal profile to the current macOS appearance mode once:
74
+ ```shell
75
+ auto-terminal-profile config set dark 'Clear Dark'
76
+ auto-terminal-profile config set light 'Clear Light'
77
+ ```
78
+ </details>
34
79
 
35
- ```shell
36
- auto-terminal-profile update-profile
37
- ```
80
+ 1. Enable automatic switching
38
81
 
39
- To sync the Terminal profile to the current macOS appearance mode when Terminal app is opened, you can add that line to your shell startup script (e.g. `.zshrc`), but it will increase the startup time of new shell sessions.
82
+ ```shell
83
+ auto-terminal-profile watch
84
+ ```
40
85
 
41
- ### Disable automatic profile switching
86
+ The process will continue until you stop it with <kbd>Ctrl</kbd>+<kbd>C</kbd>
42
87
 
43
- ```shell
44
- auto-terminal-profile disable
45
- ```
88
+ ---
46
89
 
47
- ### Help
90
+ ### Related
48
91
 
49
- ```shell
50
- auto-terminal-profile --help
51
- ```
92
+ - [patrik-csak/mac-terminal](https://github.com/patrik-csak/mac-terminal) · Node.js library to control the macOS Terminal app, used by this app
@@ -0,0 +1,3 @@
1
+ export {default as setMode} from './set-mode.js';
2
+ export {default as set} from './set.js';
3
+ export {default as show} from './show.js';
@@ -0,0 +1,24 @@
1
+ import {consola} from 'consola';
2
+ import {assertTerminalProfile, setTerminalProfile} from 'mac-terminal';
3
+ import {getConfig, getCurrentMode} from '#library';
4
+
5
+ /**
6
+ Set the Terminal profile for an appearance mode
7
+
8
+ @param {{mode: 'dark' | 'light', profile: string}} parameters - Mode and profile to save
9
+ @throws {Error}
10
+ @returns {Promise<void>}
11
+ */
12
+ export default async function setMode({mode, profile}) {
13
+ await assertTerminalProfile(profile);
14
+
15
+ const config = await getConfig();
16
+
17
+ config.set(`profiles.${mode}`, profile);
18
+
19
+ consola.success('saved configuration');
20
+
21
+ if (mode === (await getCurrentMode())) {
22
+ await setTerminalProfile({profile, setDefault: true});
23
+ }
24
+ }
@@ -0,0 +1,44 @@
1
+ import {consola} from 'consola';
2
+ import {getTerminalProfiles, setTerminalProfile} from 'mac-terminal';
3
+ import {getConfig, getCurrentMode, modes} from '#library';
4
+
5
+ /**
6
+ Prompt for and save Terminal profiles for both appearance modes
7
+
8
+ @returns {Promise<void>}
9
+ */
10
+ export default async function set() {
11
+ const config = await getConfig();
12
+ const profiles = await getTerminalProfiles();
13
+ const newProfiles = {};
14
+
15
+ for (const mode of modes) {
16
+ // eslint-disable-next-line no-await-in-loop
17
+ const selectedProfile = await consola.prompt(
18
+ `select ${mode} mode profile`,
19
+ {
20
+ cancel: 'undefined',
21
+ initial: config.get(`profiles.${mode}`),
22
+ options: profiles,
23
+ type: 'select',
24
+ },
25
+ );
26
+
27
+ if (selectedProfile === undefined) {
28
+ return;
29
+ }
30
+
31
+ newProfiles[mode] = selectedProfile;
32
+ }
33
+
34
+ config.set('profiles', newProfiles);
35
+
36
+ consola.success('saved configuration');
37
+
38
+ const currentMode = await getCurrentMode();
39
+
40
+ await setTerminalProfile({
41
+ profile: newProfiles[currentMode],
42
+ setDefault: true,
43
+ });
44
+ }
@@ -0,0 +1,23 @@
1
+ // eslint-disable-next-line n/prefer-global/console
2
+ import console from 'node:console';
3
+ import {styleText} from 'node:util';
4
+ import {getConfig, modes} from '#library';
5
+
6
+ /**
7
+ Show the configured Terminal profile for both appearance modes
8
+
9
+ @returns {Promise<void>}
10
+ */
11
+ export default async function show() {
12
+ const config = await getConfig();
13
+
14
+ for (const mode of modes) {
15
+ const configuredMode = config.get(`profiles.${mode}`);
16
+ let icon = mode === 'dark'
17
+ ? '\u{263D}' // Moon
18
+ : '\u{2600}'; // Sun
19
+ icon = styleText('yellow', icon);
20
+
21
+ console.log(`${icon} ${mode} mode profile: ${configuredMode}`);
22
+ }
23
+ }
@@ -0,0 +1,3 @@
1
+ export * as config from './config/index.js';
2
+ export {default as update} from './update.js';
3
+ export {default as watch} from './watch.js';
@@ -0,0 +1,17 @@
1
+ import {setTerminalProfile} from 'mac-terminal';
2
+ import {getConfig, getCurrentMode} from '#library';
3
+
4
+ /**
5
+ Update the Terminal profile for an appearance mode
6
+
7
+ @param {{mode?: 'dark' | 'light'}} parameters - Optional appearance mode. Defaults to current mode.
8
+ @returns {Promise<void>}
9
+ */
10
+ export default async function update({mode}) {
11
+ mode ??= await getCurrentMode();
12
+
13
+ const config = await getConfig();
14
+ const profile = config.get(`profiles.${mode}`);
15
+
16
+ await setTerminalProfile({profile, setDefault: true});
17
+ }
@@ -0,0 +1,13 @@
1
+ import darkMode from 'dark-mode';
2
+ import update from './update.js';
3
+
4
+ /**
5
+ Watch for appearance mode changes and update the Terminal profile
6
+
7
+ @returns {Promise<void>}
8
+ */
9
+ export default async function watch() {
10
+ darkMode.watch(isDarkMode => {
11
+ update({mode: isDarkMode ? 'dark' : 'light'});
12
+ });
13
+ }
@@ -0,0 +1,8 @@
1
+ import {Command} from 'commander';
2
+ import set from './set.js';
3
+ import show from './show.js';
4
+
5
+ export default new Command('config')
6
+ .description('manage configuration')
7
+ .addCommand(show)
8
+ .addCommand(set);
@@ -0,0 +1 @@
1
+ export {default} from './config.js';
@@ -0,0 +1,24 @@
1
+ import {Command} from 'commander';
2
+ import * as actions from '#cli/actions';
3
+
4
+ /**
5
+ Make set mode command
6
+
7
+ @param {'dark' | 'light'} mode - Appearance mode
8
+ */
9
+ export default function setMode(mode) {
10
+ return new Command(mode)
11
+ .description(`set terminal profile for ${mode}`)
12
+ .argument('<profile>', 'terminal profile name')
13
+ .action(async function (profile) {
14
+ try {
15
+ await actions.config.setMode({mode, profile});
16
+ } catch (error) {
17
+ if (error instanceof Error) {
18
+ this.error(error.message);
19
+ }
20
+
21
+ throw error;
22
+ }
23
+ });
24
+ }
@@ -0,0 +1,15 @@
1
+ import {Command} from 'commander';
2
+ import setMode from './set-mode.js';
3
+ import * as actions from '#cli/actions';
4
+ import {modes} from '#library';
5
+
6
+ const command = new Command('set').description('update configuration');
7
+
8
+ for (const mode of modes) {
9
+ command.addCommand(setMode(mode));
10
+ }
11
+
12
+ // eslint-disable-next-line unicorn/no-top-level-side-effects
13
+ command.action(actions.config.set);
14
+
15
+ export default command;
@@ -0,0 +1,6 @@
1
+ import {Command} from 'commander';
2
+ import * as actions from '#cli/actions';
3
+
4
+ export default new Command('show')
5
+ .description('show configuration')
6
+ .action(actions.config.show);
@@ -0,0 +1,3 @@
1
+ export {default as config} from './config/index.js';
2
+ export {default as update} from './update.js';
3
+ export {default as watch} from './watch.js';
@@ -0,0 +1,11 @@
1
+ import {Argument, Command} from 'commander';
2
+ import * as actions from '#cli/actions';
3
+ import {modes} from '#library';
4
+
5
+ export default new Command('update')
6
+ .description('update terminal profile based on the mode')
7
+ .addArgument(new Argument(
8
+ '[mode]',
9
+ 'appearance mode. defaults to current system appearance mode.',
10
+ ).choices(modes))
11
+ .action(async mode => actions.update({mode}));
@@ -0,0 +1,6 @@
1
+ import {Command} from 'commander';
2
+ import * as actions from '#cli/actions';
3
+
4
+ export default new Command('watch')
5
+ .description('watch for appearance mode changes and update the terminal profile')
6
+ .action(actions.watch);
package/source/cli.js ADDED
@@ -0,0 +1,17 @@
1
+ #! /usr/bin/env node
2
+
3
+ import {program} from 'commander';
4
+ import * as commands from '#cli/commands';
5
+ import packageJson from '#package-json' with {type: 'json'};
6
+
7
+ program
8
+ .name(packageJson.name)
9
+ .description(packageJson.description)
10
+ .version(packageJson.version);
11
+
12
+ program
13
+ .addCommand(commands.config)
14
+ .addCommand(commands.update)
15
+ .addCommand(commands.watch);
16
+
17
+ await program.parseAsync();
@@ -0,0 +1,32 @@
1
+ import Conf from 'conf';
2
+ import {getTerminalDefaultProfile} from 'mac-terminal';
3
+ import packageJson from '#package-json' with {type: 'json'};
4
+
5
+ export default async function getConfig() {
6
+ const defaultProfile = await getTerminalDefaultProfile();
7
+
8
+ const config = new Conf({
9
+ defaults: {
10
+ profiles: {
11
+ dark: defaultProfile,
12
+ light: defaultProfile,
13
+ },
14
+ },
15
+ projectName: packageJson.name,
16
+ schema: {
17
+ profiles: {
18
+ properties: {
19
+ dark: {
20
+ type: 'string',
21
+ },
22
+ light: {
23
+ type: 'string',
24
+ },
25
+ },
26
+ type: 'object',
27
+ },
28
+ },
29
+ });
30
+
31
+ return config;
32
+ }
@@ -0,0 +1,10 @@
1
+ import darkMode from 'dark-mode';
2
+
3
+ /**
4
+ Get the current appearance mode
5
+
6
+ @returns {Promise<'dark' | 'light'>} The current appearance mode
7
+ */
8
+ export default async function getCurrentMode() {
9
+ return (await darkMode.isEnabled()) ? 'dark' : 'light';
10
+ }
@@ -0,0 +1,3 @@
1
+ export {default as getConfig} from './get-config.js';
2
+ export {default as getCurrentMode} from './get-current-mode.js';
3
+ export {default as modes} from './modes.js';
@@ -0,0 +1,3 @@
1
+ const modes = ['dark', 'light'];
2
+
3
+ export default modes;
@@ -1 +0,0 @@
1
- buy_me_a_coffee: patrikcsak
@@ -1,7 +0,0 @@
1
- import {disableAutomaticSwitching} from '../functions/index.js';
2
-
3
- export async function disable() {
4
- await disableAutomaticSwitching();
5
-
6
- console.log('Automatic switching disabled');
7
- }
package/actions/enable.js DELETED
@@ -1,58 +0,0 @@
1
- import {config} from '../config.js';
2
- import {packageJson} from '../constants/index.js';
3
- import {
4
- enableAutomaticSwitching,
5
- getCurrentMode,
6
- isTerminalOpen,
7
- setTerminalProfile,
8
- } from '../functions/index.js';
9
-
10
- /**
11
- * @param {string} mode
12
- */
13
- function undefinedProfileMessage(mode) {
14
- return `${mode} profile must be specified with --${mode}-profile or previously set with \`${packageJson.name} set-${mode}-mode\``;
15
- }
16
-
17
- /**
18
- * @param {object} parameters
19
- * @param {string|undefined} parameters.darkProfile
20
- * @param {string|undefined} parameters.lightProfile
21
- */
22
- export async function enable(parameters) {
23
- if (
24
- [parameters.darkProfile, config.darkProfile].every(
25
- (value) => value === undefined,
26
- )
27
- ) {
28
- throw new Error(undefinedProfileMessage('dark'));
29
- }
30
-
31
- if (
32
- [parameters.lightProfile, config.lightProfile].every(
33
- (value) => value === undefined,
34
- )
35
- ) {
36
- throw new Error(undefinedProfileMessage('light'));
37
- }
38
-
39
- if (parameters.darkProfile !== undefined) {
40
- config.darkProfile = parameters.darkProfile;
41
- }
42
-
43
- if (parameters.lightProfile !== undefined) {
44
- config.lightProfile = parameters.lightProfile;
45
- }
46
-
47
- await enableAutomaticSwitching();
48
-
49
- if (await isTerminalOpen()) {
50
- const mode = await getCurrentMode();
51
-
52
- if (parameters[`${mode}Profile`] !== undefined) {
53
- await setTerminalProfile(config[`${mode}Profile`]);
54
- }
55
- }
56
-
57
- console.log('automatic switching enabled');
58
- }
package/actions/index.js DELETED
@@ -1,5 +0,0 @@
1
- export {disable} from './disable.js';
2
- export {enable} from './enable.js';
3
- export {setModeProfile} from './set-mode-profile.js';
4
- export {status} from './status.js';
5
- export {updateProfile} from './update-profile.js';
@@ -1,21 +0,0 @@
1
- import {config} from '../config.js';
2
- import {
3
- getCurrentMode,
4
- isAutomaticSwitchingEnabled,
5
- isTerminalOpen,
6
- setTerminalProfile,
7
- } from '../functions/index.js';
8
-
9
- export async function setModeProfile({mode, profile}) {
10
- config[`${mode}Profile`] = profile;
11
-
12
- if ((await isAutomaticSwitchingEnabled()) && (await isTerminalOpen())) {
13
- const currentMode = await getCurrentMode();
14
-
15
- if (currentMode === mode) {
16
- await setTerminalProfile(profile);
17
- }
18
- }
19
-
20
- console.log(`${mode} mode profile set to '${profile}'`);
21
- }
package/actions/status.js DELETED
@@ -1,12 +0,0 @@
1
- import {isAutomaticSwitchingEnabled} from '../functions/index.js';
2
- import {config} from '../config.js';
3
-
4
- export async function status() {
5
- console.log(
6
- `automatic switching : ${
7
- (await isAutomaticSwitchingEnabled()) ? 'enabled' : 'disabled'
8
- }`,
9
- );
10
- console.log(`dark profile : ${config.darkProfile}`);
11
- console.log(`light profile : ${config.lightProfile}`);
12
- }
@@ -1,26 +0,0 @@
1
- import {config} from '../config.js';
2
- import {
3
- getCurrentMode,
4
- isAutomaticSwitchingEnabled,
5
- isTerminalOpen,
6
- setTerminalProfile,
7
- } from '../functions/index.js';
8
-
9
- export async function updateProfile() {
10
- if (!(await isAutomaticSwitchingEnabled()) || !(await isTerminalOpen())) {
11
- return;
12
- }
13
-
14
- if (!config.darkProfile) {
15
- throw new Error('Dark profile not set');
16
- }
17
-
18
- if (!config.lightProfile) {
19
- throw new Error('Light profile not set');
20
- }
21
-
22
- const mode = await getCurrentMode();
23
- const profile = config[`${mode}Profile`];
24
-
25
- await setTerminalProfile(profile);
26
- }
package/changelog.md DELETED
@@ -1,84 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [5.0.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v4.0.0...v5.0.0) – 2024-11-27
9
-
10
- ### Changed
11
-
12
- - **BREAKING**: `enable` and `set-(dark|light)-profile` now set the Terminal profile
13
- - Updated dependencies
14
-
15
- ## [4.0.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v3.0.2...v4.0.0) – 2024-03-25
16
-
17
- ### Added
18
-
19
- - Documentation explaining how to automatically update Terminal profile when opening Terminal
20
-
21
- ### Changed
22
-
23
- - **BREAKING**: `update-profile` gets appearance mode from OS instead of from `DARKMODE` environment variable
24
-
25
- ## [3.0.2](https://github.com/patrik-csak/auto-terminal-profile/compare/v3.0.1...v3.0.2) – 2024-02-21
26
-
27
- ### Fixed
28
-
29
- - Fix Terminal opening when closed
30
-
31
- ## [3.0.1](https://github.com/patrik-csak/auto-terminal-profile/compare/v3.0.0...v3.0.1) – 2024-02-20
32
-
33
- ### Fixed
34
-
35
- - Fix broken post-install compilation step
36
-
37
- ## [3.0.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v2.1.0...v3.0.0) – 2024-02-19
38
-
39
- ### Changed
40
-
41
- - **BREAKING**: `update-profile` gets appearance mode from `DARKMODE` environment variable instead of from OS
42
-
43
- ### Removed
44
-
45
- - Support for Node.js versions before 18
46
-
47
- ### Fixed
48
-
49
- - Fix issue causing `auto-terminal-profile` to silently fail on macOS Sonoma
50
-
51
- ## [2.1.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v2.0.0...v2.1.0) – 2023-07-04
52
-
53
- ### Changed
54
-
55
- - Update dependencies
56
-
57
- ## [2.0.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v1.1.1...v2.0.0) – 2023-05-10
58
-
59
- ### Added
60
-
61
- - Support for Node.js v20
62
-
63
- ### Removed
64
-
65
- - **BREAKING**: Support for Node.js v14
66
-
67
- ## [1.1.1](https://github.com/patrik-csak/auto-terminal-profile/compare/v1.1.0...v1.1.1) – 2023-03-22
68
-
69
- ### Changed
70
-
71
- - Update dependencies with security vulnerabilities
72
-
73
- ## [1.1.0](https://github.com/patrik-csak/auto-terminal-profile/compare/v1.0.1...v1.1.0) – 2023-03-15
74
-
75
- ### Added
76
-
77
- - Update Terminal’s default profile on appearance mode switch so that Terminal will use the correct profile when opened after appearance mode switch.
78
-
79
- ## [1.0.1](https://github.com/patrik-csak/auto-terminal-profile/compare/v1.0.0...v1.0.1) – 2022-12-03
80
-
81
- ### Added
82
-
83
- - Support for Node.js v18 and v19
84
- - Changelog
package/cli.js DELETED
@@ -1,60 +0,0 @@
1
- #! /usr/bin/env node
2
-
3
- import {program} from 'commander';
4
- import {packageJson} from './constants/index.js';
5
- import {
6
- disable,
7
- enable,
8
- setModeProfile,
9
- status,
10
- updateProfile,
11
- } from './actions/index.js';
12
-
13
- program
14
- .name(packageJson.name)
15
- .description(packageJson.description)
16
- .version(packageJson.version);
17
-
18
- program
19
- .command('disable')
20
- .description(
21
- 'disable automatic macOS Terminal profile switching based on system dark / light mode',
22
- )
23
- .action(disable);
24
-
25
- program
26
- .command('enable')
27
- .description(
28
- 'enable automatic macOS Terminal profile switching based on system dark / light mode',
29
- )
30
- .option(
31
- '--dark-profile <profile>',
32
- 'dark profile name, for example "One Dark"',
33
- )
34
- .option(
35
- '--light-profile <profile>',
36
- 'light profile name, for example "One Light"',
37
- )
38
- .action(enable);
39
-
40
- for (const mode of ['dark', 'light']) {
41
- program
42
- .command(`set-${mode}-profile`)
43
- .description(`set the Terminal profile to use in ${mode} mode`)
44
- .argument('<profile>')
45
- .action((profile) => setModeProfile({mode, profile}));
46
- }
47
-
48
- program
49
- .command('status')
50
- .description('show status and configuration')
51
- .action(status);
52
-
53
- program
54
- .command('update-profile')
55
- .description(
56
- 'update the profile of currently running Terminal windows / tabs',
57
- )
58
- .action(updateProfile);
59
-
60
- program.parse();
package/config.js DELETED
@@ -1,43 +0,0 @@
1
- import Conf from 'conf';
2
- import {readPackageUp} from 'read-package-up';
3
-
4
- const {packageJson} = await readPackageUp({cwd: new URL('.', import.meta.url)});
5
-
6
- const config_ = new Conf({projectName: packageJson.name});
7
-
8
- class Config {
9
- keys = {
10
- darkProfile: 'darkProfile',
11
- lightProfile: 'lightProfile',
12
- };
13
-
14
- /**
15
- * @return {string|undefined}
16
- */
17
- get darkProfile() {
18
- return config_.get(this.keys.darkProfile);
19
- }
20
-
21
- /**
22
- * @param {string} profile
23
- */
24
- set darkProfile(profile) {
25
- config_.set(this.keys.darkProfile, profile);
26
- }
27
-
28
- /**
29
- * @return {string|undefined}
30
- */
31
- get lightProfile() {
32
- return config_.get(this.keys.lightProfile);
33
- }
34
-
35
- /**
36
- * @param {string} profile
37
- */
38
- set lightProfile(profile) {
39
- config_.set(this.keys.lightProfile, profile);
40
- }
41
- }
42
-
43
- export const config = new Config();
@@ -1,2 +0,0 @@
1
- export {launchAgentPlistFilePath} from './launch-agent-plist-file-path.js';
2
- export {packageJson} from './package-json.js';
@@ -1,5 +0,0 @@
1
- import untildify from 'untildify';
2
-
3
- export const launchAgentPlistFilePath = untildify(
4
- '~/Library/LaunchAgents/ke.bou.dark-mode-notify.plist',
5
- );
@@ -1,5 +0,0 @@
1
- import {readPackageUp} from 'read-package-up';
2
-
3
- export const {packageJson} = await readPackageUp({
4
- cwd: new URL('.', import.meta.url),
5
- });
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2021 Bouke van der Bijl
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,17 +0,0 @@
1
- prefix ?= /usr/local
2
- bindir = $(prefix)/bin
3
-
4
- build:
5
- swift build -c release --disable-sandbox
6
-
7
- install: build
8
- install -d "$(bindir)"
9
- install ".build/release/dark-mode-notify" "$(bindir)"
10
-
11
- uninstall:
12
- rm -rf "$(bindir)/dark-mode-notify"
13
-
14
- clean:
15
- rm -rf .build
16
-
17
- .PHONY: build install uninstall clean
@@ -1,15 +0,0 @@
1
- // swift-tools-version:4.0
2
- import PackageDescription
3
-
4
- let package = Package(
5
- name: "dark-mode-notify",
6
- dependencies: [
7
- ],
8
- targets: [
9
- .target(
10
- name: "dark-mode-notify",
11
- path: "."
12
- )
13
- ]
14
- )
15
-
@@ -1,48 +0,0 @@
1
- # dark-mode-notify
2
-
3
- This small Swift program will run a command whenever the dark mode status changes on macOS. You can use it to change your vim color config automatically for example.
4
-
5
- ## Usage
6
-
7
- Use make to compile the program, then run directly:
8
-
9
- ```shell
10
- .build/release/dark-mode-notify <your-program>
11
- ```
12
-
13
- Alternatively you can install it by doing `make install`.
14
-
15
- The program will be run immediately when the command starts, and every time the OS goes from dark mode to light mode or back. The environment variable `DARKMODE` will be set to either `1` or `0`.
16
-
17
- ## Background agent
18
-
19
- To keep this program running in the background, compile the binary to somewhere and create the following file at `~/Library/LaunchAgents/ke.bou.dark-mode-notify.plist`. Don't forget to replace the arguments and the path to the logs (which comes in handy for debugging)
20
-
21
- ```xml
22
- <?xml version="1.0" encoding="UTF-8"?>
23
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
24
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
25
- <plist version="1.0">
26
- <dict>
27
- <key>Label</key>
28
- <string>ke.bou.dark-mode-notify</string>
29
- <key>KeepAlive</key>
30
- <true/>
31
- <key>StandardErrorPath</key>
32
- <string>----Path to a location----/dark-mode-notify-stderr.log</string>
33
- <key>StandardOutPath</key>
34
- <string>----Path to a location----/dark-mode-notify-stdout.log</string>
35
- <key>ProgramArguments</key>
36
- <array>
37
- <string>/usr/local/bin/dark-mode-notify</string>
38
- <string>--- Path to your script ---</string>
39
- </array>
40
- </dict>
41
- </plist>
42
- ```
43
-
44
- Then `launchctl load -w ~/Library/LaunchAgents/ke.bou.dark-mode-notify.plist` will keep it running on boot.
45
-
46
- ## Credit
47
-
48
- This script is a lightly modified version of https://github.com/mnewt/dotemacs/blob/master/bin/dark-mode-notifier.swift
@@ -1,42 +0,0 @@
1
- // The program will have the DARKMODE env flag set to 1 or 0
2
- // Compile with:
3
- // swift build
4
- // And run the binary directly
5
- // Most credit goes to https://github.com/mnewt/dotemacs/blob/master/bin/dark-mode-notifier.swift
6
-
7
- import Cocoa
8
-
9
- @discardableResult
10
- func shell(_ args: [String]) -> Int32 {
11
- let task = Process()
12
- let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"
13
- var env = ProcessInfo.processInfo.environment
14
- env["DARKMODE"] = isDark ? "1" : "0"
15
- task.environment = env
16
- task.launchPath = "/usr/bin/env"
17
- task.arguments = args
18
- task.standardError = FileHandle.standardError
19
- task.standardOutput = FileHandle.standardOutput
20
- task.launch()
21
- task.waitUntilExit()
22
- return task.terminationStatus
23
- }
24
-
25
- let args = Array(CommandLine.arguments.suffix(from: 1))
26
- shell(args)
27
-
28
- DistributedNotificationCenter.default.addObserver(
29
- forName: Notification.Name("AppleInterfaceThemeChangedNotification"),
30
- object: nil,
31
- queue: nil) { (notification) in
32
- shell(args)
33
- }
34
-
35
- NSWorkspace.shared.notificationCenter.addObserver(
36
- forName: NSWorkspace.didWakeNotification,
37
- object: nil,
38
- queue: nil) { (notification) in
39
- shell(args)
40
- }
41
-
42
- NSApplication.shared.run()
@@ -1,9 +0,0 @@
1
- import {unlink} from 'node:fs/promises';
2
- import {execa} from 'execa';
3
- import {launchAgentPlistFilePath} from '../constants/index.js';
4
-
5
- export async function disableAutomaticSwitching() {
6
- await execa`launchctl unload -w ${launchAgentPlistFilePath}`;
7
-
8
- await unlink(launchAgentPlistFilePath);
9
- }
@@ -1,13 +0,0 @@
1
- import {writeFile} from 'node:fs/promises';
2
- import {execa} from 'execa';
3
- import {launchAgentPlistFilePath} from '../constants/index.js';
4
- import {getLaunchAgentPlistFileContents} from './get-launch-agent-plist-file-contents.js';
5
-
6
- export async function enableAutomaticSwitching() {
7
- await writeFile(
8
- launchAgentPlistFilePath,
9
- await getLaunchAgentPlistFileContents(),
10
- );
11
-
12
- await execa`launchctl load -w ${launchAgentPlistFilePath}`;
13
- }
@@ -1,8 +0,0 @@
1
- import darkMode from 'dark-mode';
2
-
3
- /**
4
- * @returns {Promise<'dark' | 'light'>} Current macOS appearance mode
5
- */
6
- export async function getCurrentMode() {
7
- return (await darkMode.isEnabled()) ? 'dark' : 'light';
8
- }
@@ -1,27 +0,0 @@
1
- import {readFile} from 'node:fs/promises';
2
- import {fileURLToPath} from 'node:url';
3
- import process from 'node:process';
4
- import pupa from 'pupa';
5
- import envPaths from 'env-paths';
6
- import {packageJson} from '../constants/index.js';
7
-
8
- export async function getLaunchAgentPlistFileContents() {
9
- return pupa(
10
- await readFile(new URL('../templates/launch-agent.xml', import.meta.url), {
11
- encoding: 'utf8',
12
- }),
13
- {
14
- autoTerminalProfilePath: fileURLToPath(
15
- new URL('../cli.js', import.meta.url),
16
- ),
17
- darkModeNotifyPath: fileURLToPath(
18
- new URL(
19
- '../dark-mode-notify/.build/release/dark-mode-notify',
20
- import.meta.url,
21
- ),
22
- ),
23
- logPath: envPaths(packageJson.name).log,
24
- path: process.env.PATH,
25
- },
26
- );
27
- }
@@ -1,7 +0,0 @@
1
- export {enableAutomaticSwitching} from './enable-automatic-switching.js';
2
- export {disableAutomaticSwitching} from './disable-automatic-switching.js';
3
- export {getCurrentMode} from './get-current-mode.js';
4
- export {getLaunchAgentPlistFileContents} from './get-launch-agent-plist-file-contents.js';
5
- export {isAutomaticSwitchingEnabled} from './is-automatic-switching-enabled.js';
6
- export {isTerminalOpen} from './is-terminal-open.js';
7
- export {setTerminalProfile} from './set-terminal-profile.js';
@@ -1,32 +0,0 @@
1
- import {existsSync as exists} from 'node:fs';
2
- import {execa} from 'execa';
3
- import {launchAgentPlistFilePath} from '../constants/index.js';
4
-
5
- /**
6
- * @return {Promise<boolean>}
7
- */
8
- async function isDarkModeNotifyRunning() {
9
- const {stdout} = await execa`launchctl list`;
10
-
11
- return stdout.includes('ke.bou.dark-mode-notify');
12
- }
13
-
14
- /**
15
- * @return {Promise<boolean>}
16
- */
17
- export async function isAutomaticSwitchingEnabled() {
18
- const _isDarkModeNotifyRunning = await isDarkModeNotifyRunning();
19
- const plistFileExists = exists(launchAgentPlistFilePath);
20
-
21
- if (_isDarkModeNotifyRunning && !plistFileExists) {
22
- throw new Error(
23
- `Automatic switching is running, but the launch agent plist file (${launchAgentPlistFilePath}) doesn't exist`,
24
- );
25
- } else if (!_isDarkModeNotifyRunning && plistFileExists) {
26
- throw new Error(
27
- `Automatic switching is not running, but the launch agent plist file (${launchAgentPlistFilePath}) exists`,
28
- );
29
- }
30
-
31
- return _isDarkModeNotifyRunning && plistFileExists;
32
- }
@@ -1,18 +0,0 @@
1
- import {runAppleScript} from 'run-applescript';
2
-
3
- /**
4
- * @returns {Promise<boolean>}
5
- */
6
- export async function isTerminalOpen() {
7
- const result = await runAppleScript(`tell application "System Events"
8
- set isOpen to (name of processes) contains "Terminal"
9
- end tell
10
-
11
- if isOpen then
12
- return "true"
13
- else
14
- return "false"
15
- end if`);
16
-
17
- return result === 'true';
18
- }
@@ -1,11 +0,0 @@
1
- import {
2
- setTerminalDefaultProfile as setDefaultProfile,
3
- setTerminalProfile as setProfile,
4
- } from 'terminal-profile';
5
-
6
- /**
7
- * @param {string} profile
8
- */
9
- export async function setTerminalProfile(profile) {
10
- await Promise.all([setDefaultProfile(profile), setProfile(profile)]);
11
- }
@@ -1,31 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
3
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
4
- <plist version="1.0">
5
- <dict>
6
- <key>Label</key>
7
- <string>ke.bou.dark-mode-notify</string>
8
-
9
- <key>KeepAlive</key>
10
- <true/>
11
-
12
- <key>StandardErrorPath</key>
13
- <string>{logPath}/dark-mode-notify-stderr.log</string>
14
-
15
- <key>StandardOutPath</key>
16
- <string>{logPath}/dark-mode-notify-stdout.log</string>
17
-
18
- <key>EnvironmentVariables</key>
19
- <dict>
20
- <key>PATH</key>
21
- <string>{path}</string>
22
- </dict>
23
-
24
- <key>ProgramArguments</key>
25
- <array>
26
- <string>{darkModeNotifyPath}</string>
27
- <string>{autoTerminalProfilePath}</string>
28
- <string>update-profile</string>
29
- </array>
30
- </dict>
31
- </plist>