@terminalhere/cli 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TerminalHere Contributors
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.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # TerminalHere for npm
2
+
3
+ [![CI](https://github.com/mehmetduran932/terminalhere-npm/actions/workflows/ci.yml/badge.svg)](https://github.com/mehmetduran932/terminalhere-npm/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ Cross-platform file-manager integration for opening a folder in a terminal.
7
+
8
+ ## Install
9
+
10
+ ```powershell
11
+ npm install --global @terminalhere/cli
12
+ terminalhere install
13
+ terminalhere status
14
+ ```
15
+
16
+ Windows adds Explorer entries beneath `HKCU\\Software\\Classes` without administrator privileges. macOS installs a Finder Quick Action, while Linux installs a Nautilus Script; restart Nautilus after installation if it does not appear immediately.
17
+
18
+ ## Commands
19
+
20
+ ```text
21
+ terminalhere install | uninstall | status
22
+ terminalhere enable <terminal|powershell|cmd|gitbash|vscode>
23
+ terminalhere disable <terminal|powershell|cmd|gitbash|vscode>
24
+ terminalhere enable-all | disable-all
25
+ terminalhere open [directory]
26
+ ```
27
+
28
+ Add `--json` to `status`, `install`, or enable/disable commands for automation.
29
+
30
+ ## Security and project rules
31
+
32
+ - No administrator privileges are required or requested.
33
+ - The package changes only the current user's supported file-manager integration locations.
34
+ - Report vulnerabilities privately; see [SECURITY.md](SECURITY.md).
35
+ - Contributions follow the fork/PR, branch naming, review, and CI requirements in
36
+ [CONTRIBUTING.md](CONTRIBUTING.md).
37
+ - This repository is public, but no npm package has been published from it.
38
+
39
+ ## Development
40
+
41
+ ```bash
42
+ npm install
43
+ npm test
44
+ npm run build
45
+ npm pack --dry-run
46
+ ```
47
+
48
+ No npm release has been published from this repository.
49
+
50
+ ## Package migration
51
+
52
+ `@mdsoft2026/terminalhere` has been replaced by `@terminalhere/cli`. The
53
+ `terminalhere` command is unchanged; reinstall the package under its new name.
package/dist/apps.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { AppInfo, TerminalTarget } from './types.js';
2
+ export declare function detectApp(target: TerminalTarget): Promise<AppInfo>;
3
+ export declare const targets: TerminalTarget[];
4
+ export declare function commandFor(target: TerminalTarget, executablePath: string, token: '%V' | '%1'): string;
package/dist/apps.js ADDED
@@ -0,0 +1,88 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { delimiter, join } from 'node:path';
3
+ const targetDetails = {
4
+ terminal: {
5
+ target: 'terminal',
6
+ displayName: 'Open in Terminal',
7
+ registryKeyName: 'TerminalHere.WindowsTerminal',
8
+ },
9
+ powershell: {
10
+ target: 'powershell',
11
+ displayName: 'Open in PowerShell',
12
+ registryKeyName: 'TerminalHere.PowerShell',
13
+ },
14
+ cmd: {
15
+ target: 'cmd',
16
+ displayName: 'Open in Command Prompt',
17
+ registryKeyName: 'TerminalHere.CommandPrompt',
18
+ },
19
+ gitbash: {
20
+ target: 'gitbash',
21
+ displayName: 'Open in Git Bash',
22
+ registryKeyName: 'TerminalHere.GitBash',
23
+ },
24
+ vscode: {
25
+ target: 'vscode',
26
+ displayName: 'Open in VS Code',
27
+ registryKeyName: 'TerminalHere.VSCode',
28
+ },
29
+ };
30
+ const candidates = {
31
+ terminal: [],
32
+ powershell: [],
33
+ cmd: process.env.ComSpec ? [process.env.ComSpec] : [],
34
+ gitbash: ['C:\\Program Files\\Git\\git-bash.exe', 'C:\\Program Files (x86)\\Git\\git-bash.exe'],
35
+ vscode: [
36
+ join(process.env.LOCALAPPDATA ?? '', 'Programs', 'Microsoft VS Code', 'Code.exe'),
37
+ 'C:\\Program Files\\Microsoft VS Code\\Code.exe',
38
+ ],
39
+ };
40
+ async function exists(path) {
41
+ try {
42
+ await access(path);
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ async function findOnPath(names) {
50
+ const paths = (process.env.PATH ?? '').split(delimiter).filter(Boolean);
51
+ for (const directory of paths) {
52
+ for (const name of names) {
53
+ const candidate = join(directory, name);
54
+ if (await exists(candidate))
55
+ return candidate;
56
+ }
57
+ }
58
+ return undefined;
59
+ }
60
+ export async function detectApp(target) {
61
+ const details = targetDetails[target];
62
+ const pathNames = {
63
+ terminal: ['wt.exe'],
64
+ powershell: ['powershell.exe'],
65
+ cmd: ['cmd.exe'],
66
+ gitbash: ['git-bash.exe'],
67
+ vscode: ['Code.exe'],
68
+ };
69
+ const executablePath = (await findOnPath(pathNames[target])) ??
70
+ (await Promise.all(candidates[target].map(async (path) => ((await exists(path)) ? path : undefined)))).find(Boolean);
71
+ return { ...details, executablePath, iconPath: executablePath };
72
+ }
73
+ export const targets = Object.keys(targetDetails);
74
+ export function commandFor(target, executablePath, token) {
75
+ switch (target) {
76
+ case 'terminal':
77
+ return `wt.exe -d "${token}"`;
78
+ case 'powershell':
79
+ return `powershell.exe -NoExit -Command "Set-Location -LiteralPath '${token}'"`;
80
+ case 'cmd':
81
+ return `cmd.exe /K cd /d "${token}"`;
82
+ case 'gitbash':
83
+ return `"${executablePath}" --cd="${token}"`;
84
+ case 'vscode':
85
+ return `"${executablePath}" "${token}"`;
86
+ }
87
+ }
88
+ //# sourceMappingURL=apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.js","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ import { PlatformIntegration } from './platform.js';
3
+ import { targets } from './apps.js';
4
+ const commands = [
5
+ 'install',
6
+ 'uninstall',
7
+ 'status',
8
+ 'enable',
9
+ 'disable',
10
+ 'enable-all',
11
+ 'disable-all',
12
+ 'open',
13
+ ];
14
+ function usage() {
15
+ return `TerminalHere\n\nUsage: terminalhere <${commands.join('|')}> [target] [--json]\nTargets: ${targets.join(', ')}`;
16
+ }
17
+ function isTarget(value) {
18
+ return Boolean(value && targets.includes(value));
19
+ }
20
+ function print(statuses, json) {
21
+ if (json)
22
+ console.log(JSON.stringify(statuses, null, 2));
23
+ else
24
+ for (const item of statuses)
25
+ console.log(`${item.displayName}: ${item.installed ? 'Available' : 'Not found'} / ${item.enabled ? 'Enabled' : 'Disabled'}`);
26
+ }
27
+ async function main() {
28
+ const [command, target, ...flags] = process.argv.slice(2);
29
+ const json = flags.includes('--json') || target === '--json';
30
+ if (!command || command === '--help' || command === '-h') {
31
+ console.log(usage());
32
+ return;
33
+ }
34
+ const service = new PlatformIntegration();
35
+ if (command === 'install' || command === 'enable-all')
36
+ return void print(await service.install(isTarget(target) ? target : 'terminal'), json);
37
+ if (command === 'uninstall' || command === 'disable-all')
38
+ return void print(await service.uninstall(isTarget(target) ? target : 'terminal'), json);
39
+ if (command === 'status')
40
+ return void print(await service.getStatus(isTarget(target) ? target : undefined), json);
41
+ if (command === 'open')
42
+ return service.open(target && target !== '--json' ? target : undefined);
43
+ if ((command === 'enable' || command === 'disable') && isTarget(target)) {
44
+ print(command === 'enable' ? await service.install(target) : await service.uninstall(target), json);
45
+ return;
46
+ }
47
+ throw new Error(usage());
48
+ }
49
+ main().catch((error) => {
50
+ console.error(error instanceof Error ? error.message : error);
51
+ process.exitCode = 1;
52
+ });
53
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from './apps.js';
2
+ export * from './registry.js';
3
+ export * from './service.js';
4
+ export * from './platform.js';
5
+ export * from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './apps.js';
2
+ export * from './registry.js';
3
+ export * from './service.js';
4
+ export * from './platform.js';
5
+ export * from './types.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { TerminalStatus, TerminalTarget } from './types.js';
2
+ export declare class PlatformIntegration {
3
+ private readonly windows;
4
+ install(target?: TerminalTarget): Promise<TerminalStatus[]>;
5
+ uninstall(target?: TerminalTarget): Promise<TerminalStatus[]>;
6
+ getStatus(target?: TerminalTarget): Promise<TerminalStatus[]>;
7
+ open(directory?: string): Promise<void>;
8
+ }
@@ -0,0 +1,134 @@
1
+ import { execFile as execFileCallback } from 'node:child_process';
2
+ import { chmod, mkdir, rm, stat, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { ContextMenuService } from './service.js';
7
+ import { RegExeClient } from './registry.js';
8
+ const execFile = promisify(execFileCallback);
9
+ const macWorkflow = join(homedir(), 'Library', 'Services', 'TerminalHere.workflow');
10
+ const linuxScript = join(homedir(), '.local', 'share', 'nautilus', 'scripts', 'TerminalHere');
11
+ const finderWorkflow = [
12
+ '<?xml version="1.0" encoding="UTF-8"?>',
13
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
14
+ '<plist version="1.0"><dict><key>AMDocumentVersion</key><string>2</string><key>AMWorkflowType</key><string>Service</string>',
15
+ '<key>actions</key><array><dict><key>action</key><dict><key>AMAccepts</key><dict><key>Container</key><string>List</string><key>Optional</key><true/><key>Types</key><array><string>com.apple.cocoa.path</string></array></dict>',
16
+ '<key>AMActionVersion</key><string>2.0.3</string><key>AMApplication</key><array><string>Automator</string></array><key>AMParameterProperties</key><dict><key>COMMAND_STRING</key><dict><key>default value</key><string>for f in "$@"; do osascript - "$f" &lt;&lt;\'APPLESCRIPT\'\non run argv\n tell application "Terminal"\n activate\n do script "cd " &amp; quoted form of item 1 of argv\n end tell\nend run\nAPPLESCRIPT\ndone</string></dict><key>inputMethod</key><dict><key>default value</key><integer>1</integer></dict><key>shell</key><dict><key>default value</key><string>/bin/zsh</string></dict></dict>',
17
+ '<key>AMProvides</key><dict><key>Container</key><string>List</string><key>Types</key><array><string>com.apple.cocoa.path</string></array></dict><key>ActionBundlePath</key><string>/System/Library/Automator/Run Shell Script.action</string><key>ActionName</key><string>Run Shell Script</string><key>BundleIdentifier</key><string>com.apple.RunShellScript</string><key>CFBundleVersion</key><string>2.0.3</string></dict><key>isViewVisible</key><true/></dict></array>',
18
+ '<key>workflowMetaData</key><dict><key>serviceApplicationBundleID</key><string>com.apple.finder</string><key>serviceInputTypeIdentifier</key><string>com.apple.cocoa.path</string><key>serviceOutputTypeIdentifier</key><string>com.apple.cocoa.path</string></dict></dict></plist>',
19
+ ].join('');
20
+ const nautilusScript = [
21
+ '#!/bin/sh',
22
+ 'for target in "$@"; do',
23
+ ' if command -v xdg-terminal-exec >/dev/null 2>&1; then xdg-terminal-exec --working-directory="$target" && continue; fi',
24
+ ' if command -v gnome-terminal >/dev/null 2>&1; then gnome-terminal --working-directory="$target" && continue; fi',
25
+ ' if command -v konsole >/dev/null 2>&1; then konsole --workdir "$target" && continue; fi',
26
+ ' xterm -e sh -lc \'cd "$1"; exec "$SHELL"\' sh "$target"',
27
+ 'done',
28
+ '',
29
+ ].join('\n');
30
+ function asStatus(target, displayName, enabled) {
31
+ return { target, displayName, registryKeyName: 'TerminalHere', installed: true, enabled };
32
+ }
33
+ async function fileExists(path) {
34
+ try {
35
+ await stat(path);
36
+ return true;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ }
42
+ export class PlatformIntegration {
43
+ windows = new ContextMenuService(new RegExeClient());
44
+ async install(target = 'terminal') {
45
+ if (process.platform === 'win32')
46
+ return target === 'terminal' ? this.windows.enableAll() : [await this.windows.enable(target)];
47
+ if (target !== 'terminal')
48
+ throw new Error(`${target} is currently supported on Windows only.`);
49
+ if (process.platform === 'darwin') {
50
+ const document = join(macWorkflow, 'Contents', 'document.wflow');
51
+ await mkdir(dirname(document), { recursive: true });
52
+ await writeFile(document, finderWorkflow);
53
+ return [asStatus('terminal', 'Finder Quick Action: TerminalHere', true)];
54
+ }
55
+ if (process.platform === 'linux') {
56
+ await mkdir(dirname(linuxScript), { recursive: true });
57
+ await writeFile(linuxScript, nautilusScript);
58
+ await chmod(linuxScript, 0o755);
59
+ return [asStatus('terminal', 'Nautilus Script: TerminalHere', true)];
60
+ }
61
+ throw new Error(`Unsupported platform: ${process.platform}`);
62
+ }
63
+ async uninstall(target = 'terminal') {
64
+ if (process.platform === 'win32')
65
+ return target === 'terminal'
66
+ ? this.windows.disableAll()
67
+ : [await this.windows.disable(target)];
68
+ if (target !== 'terminal')
69
+ throw new Error(`${target} is currently supported on Windows only.`);
70
+ const path = process.platform === 'darwin'
71
+ ? macWorkflow
72
+ : process.platform === 'linux'
73
+ ? linuxScript
74
+ : undefined;
75
+ if (!path)
76
+ throw new Error(`Unsupported platform: ${process.platform}`);
77
+ await rm(path, { recursive: true, force: true });
78
+ return [
79
+ asStatus('terminal', process.platform === 'darwin'
80
+ ? 'Finder Quick Action: TerminalHere'
81
+ : 'Nautilus Script: TerminalHere', false),
82
+ ];
83
+ }
84
+ async getStatus(target) {
85
+ if (process.platform === 'win32')
86
+ return target ? [await this.windows.status(target)] : this.windows.allStatuses();
87
+ if (target && target !== 'terminal')
88
+ return [
89
+ {
90
+ target,
91
+ displayName: target,
92
+ registryKeyName: 'TerminalHere',
93
+ installed: false,
94
+ enabled: false,
95
+ },
96
+ ];
97
+ if (process.platform === 'darwin')
98
+ return [
99
+ asStatus('terminal', 'Finder Quick Action: TerminalHere', await fileExists(macWorkflow)),
100
+ ];
101
+ if (process.platform === 'linux')
102
+ return [asStatus('terminal', 'Nautilus Script: TerminalHere', await fileExists(linuxScript))];
103
+ return [
104
+ {
105
+ target: 'terminal',
106
+ displayName: 'TerminalHere',
107
+ registryKeyName: 'TerminalHere',
108
+ installed: false,
109
+ enabled: false,
110
+ },
111
+ ];
112
+ }
113
+ async open(directory = process.cwd()) {
114
+ if (process.platform === 'win32') {
115
+ await execFile('wt.exe', ['-d', directory]);
116
+ return;
117
+ }
118
+ if (process.platform === 'darwin') {
119
+ await execFile('open', ['-a', 'Terminal', directory]);
120
+ return;
121
+ }
122
+ if (process.platform === 'linux') {
123
+ try {
124
+ await execFile('xdg-terminal-exec', [`--working-directory=${directory}`]);
125
+ }
126
+ catch {
127
+ await execFile('gnome-terminal', [`--working-directory=${directory}`]);
128
+ }
129
+ return;
130
+ }
131
+ throw new Error(`Unsupported platform: ${process.platform}`);
132
+ }
133
+ }
134
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { RegistryClient } from './types.js';
2
+ /** Windows Registry client using argument arrays: values are never shell-interpolated. */
3
+ export declare class RegExeClient implements RegistryClient {
4
+ private run;
5
+ keyExists(path: string): Promise<boolean>;
6
+ setDefaultValue(path: string, value: string): Promise<void>;
7
+ setStringValue(path: string, name: string, value: string): Promise<void>;
8
+ deleteTree(path: string): Promise<void>;
9
+ }
@@ -0,0 +1,37 @@
1
+ import { execFile as execFileCallback } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFile = promisify(execFileCallback);
4
+ const HKCU = 'HKCU\\';
5
+ function registryPath(path) {
6
+ return `${HKCU}${path}`;
7
+ }
8
+ /** Windows Registry client using argument arrays: values are never shell-interpolated. */
9
+ export class RegExeClient {
10
+ async run(args) {
11
+ await execFile('reg.exe', args, { windowsHide: true });
12
+ }
13
+ async keyExists(path) {
14
+ try {
15
+ await this.run(['QUERY', registryPath(path)]);
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ async setDefaultValue(path, value) {
23
+ await this.run(['ADD', registryPath(path), '/ve', '/t', 'REG_SZ', '/d', value, '/f']);
24
+ }
25
+ async setStringValue(path, name, value) {
26
+ await this.run(['ADD', registryPath(path), '/v', name, '/t', 'REG_SZ', '/d', value, '/f']);
27
+ }
28
+ async deleteTree(path) {
29
+ try {
30
+ await this.run(['DELETE', registryPath(path), '/f']);
31
+ }
32
+ catch {
33
+ // Deleting a missing key is idempotent.
34
+ }
35
+ }
36
+ }
37
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC;AAEtB,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,0FAA0F;AAC1F,MAAM,OAAO,YAAY;IACf,KAAK,CAAC,GAAG,CAAC,IAAc;QAC9B,MAAM,QAAQ,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,IAAY;QAC1B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,IAAY,EAAE,KAAa;QAC/C,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,IAAY,EAAE,IAAY,EAAE,KAAa;QAC5D,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { RegistryClient, TerminalStatus, TerminalTarget } from './types.js';
2
+ export declare class ContextMenuService {
3
+ private readonly registry;
4
+ constructor(registry: RegistryClient);
5
+ enable(target: TerminalTarget): Promise<TerminalStatus>;
6
+ disable(target: TerminalTarget): Promise<TerminalStatus>;
7
+ status(target: TerminalTarget): Promise<TerminalStatus>;
8
+ enableAll(): Promise<TerminalStatus[]>;
9
+ disableAll(): Promise<TerminalStatus[]>;
10
+ allStatuses(): Promise<TerminalStatus[]>;
11
+ private writeEntry;
12
+ }
@@ -0,0 +1,59 @@
1
+ import { commandFor, detectApp, targets } from './apps.js';
2
+ const backgroundPaths = [
3
+ 'Software\\Classes\\Directory\\Background\\shell',
4
+ 'Software\\Classes\\Drive\\Background\\shell',
5
+ ];
6
+ const directoryPaths = ['Software\\Classes\\Directory\\shell', 'Software\\Classes\\Drive\\shell'];
7
+ export class ContextMenuService {
8
+ registry;
9
+ constructor(registry) {
10
+ this.registry = registry;
11
+ }
12
+ async enable(target) {
13
+ const app = await detectApp(target);
14
+ if (!app.executablePath)
15
+ throw new Error(`${app.displayName} could not be found on this computer.`);
16
+ for (const parent of backgroundPaths)
17
+ await this.writeEntry(parent, app, '%V');
18
+ for (const parent of directoryPaths)
19
+ await this.writeEntry(parent, app, '%1');
20
+ return { ...app, installed: true, enabled: true };
21
+ }
22
+ async disable(target) {
23
+ const app = await detectApp(target);
24
+ for (const parent of [...backgroundPaths, ...directoryPaths])
25
+ await this.registry.deleteTree(`${parent}\\${app.registryKeyName}`);
26
+ return { ...app, installed: Boolean(app.executablePath), enabled: false };
27
+ }
28
+ async status(target) {
29
+ const app = await detectApp(target);
30
+ const enabled = await this.registry.keyExists(`${backgroundPaths[0]}\\${app.registryKeyName}`);
31
+ return { ...app, installed: Boolean(app.executablePath), enabled };
32
+ }
33
+ async enableAll() {
34
+ const results = [];
35
+ for (const target of targets) {
36
+ try {
37
+ results.push(await this.enable(target));
38
+ }
39
+ catch {
40
+ results.push(await this.status(target));
41
+ }
42
+ }
43
+ return results;
44
+ }
45
+ async disableAll() {
46
+ return Promise.all(targets.map((target) => this.disable(target)));
47
+ }
48
+ async allStatuses() {
49
+ return Promise.all(targets.map((target) => this.status(target)));
50
+ }
51
+ async writeEntry(parent, app, token) {
52
+ const path = `${parent}\\${app.registryKeyName}`;
53
+ await this.registry.setDefaultValue(path, app.displayName);
54
+ if (app.iconPath)
55
+ await this.registry.setStringValue(path, 'Icon', app.iconPath);
56
+ await this.registry.setDefaultValue(`${path}\\command`, commandFor(app.target, app.executablePath, token));
57
+ }
58
+ }
59
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type TerminalTarget = 'terminal' | 'powershell' | 'cmd' | 'gitbash' | 'vscode';
2
+ export interface AppInfo {
3
+ target: TerminalTarget;
4
+ displayName: string;
5
+ registryKeyName: string;
6
+ executablePath?: string;
7
+ iconPath?: string;
8
+ }
9
+ export interface TerminalStatus extends AppInfo {
10
+ installed: boolean;
11
+ enabled: boolean;
12
+ }
13
+ export interface RegistryClient {
14
+ keyExists(path: string): Promise<boolean>;
15
+ setDefaultValue(path: string, value: string): Promise<void>;
16
+ setStringValue(path: string, name: string, value: string): Promise<void>;
17
+ deleteTree(path: string): Promise<void>;
18
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@terminalhere/cli",
3
+ "version": "0.2.0",
4
+ "description": "Manage Windows Explorer terminal context-menu entries from npm.",
5
+ "type": "module",
6
+ "bin": {
7
+ "terminalhere": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "exports": "./dist/index.js",
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.json",
20
+ "test": "vitest run",
21
+ "typecheck": "tsc --noEmit",
22
+ "format": "prettier --write .",
23
+ "format:check": "prettier --check .",
24
+ "prepack": "npm run build"
25
+ },
26
+ "keywords": [
27
+ "windows",
28
+ "macos",
29
+ "linux",
30
+ "context-menu",
31
+ "terminal",
32
+ "explorer",
33
+ "finder",
34
+ "nautilus",
35
+ "cli"
36
+ ],
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/mehmetduran932/terminalhere-npm.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/mehmetduran932/terminalhere-npm/issues"
44
+ },
45
+ "homepage": "https://github.com/mehmetduran932/terminalhere-npm#readme",
46
+ "devDependencies": {
47
+ "@types/node": "^22.10.2",
48
+ "prettier": "^3.4.2",
49
+ "typescript": "^5.7.2",
50
+ "vitest": "^2.1.8"
51
+ }
52
+ }