hsh19900502 1.0.24 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/commands/url.d.ts +2 -1
- package/dist/commands/url.js +85 -1
- package/dist/hsh.js +9 -2
- package/dist/types/index.d.ts +3 -0
- package/docs/FUZZY_SEARCH_FEATURE.md +1 -0
- package/package.json +1 -1
- package/src/commands/url.ts +101 -1
- package/src/hsh.ts +10 -2
- package/src/types/index.ts +3 -0
package/README.md
CHANGED
package/dist/commands/url.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare function addUrl(name: string, url: string): Promise<void>;
|
|
2
2
|
export declare function removeUrl(name?: string): Promise<void>;
|
|
3
|
-
export declare function searchAndOpenUrl(): Promise<void>;
|
|
3
|
+
export declare function searchAndOpenUrl(suppress?: boolean): Promise<void>;
|
|
4
|
+
export declare function openUrlGroup(): Promise<void>;
|
package/dist/commands/url.js
CHANGED
|
@@ -18,6 +18,36 @@ function readFullConfig() {
|
|
|
18
18
|
return config;
|
|
19
19
|
}
|
|
20
20
|
function writeConfig(config) {
|
|
21
|
+
// Sort URLs by domain before writing
|
|
22
|
+
if (config.urls) {
|
|
23
|
+
const sortedUrls = {};
|
|
24
|
+
// Create entries with extracted domains for sorting
|
|
25
|
+
const entries = Object.entries(config.urls).map(([name, url]) => {
|
|
26
|
+
// Extract domain from URL
|
|
27
|
+
let domain = '';
|
|
28
|
+
try {
|
|
29
|
+
const urlObj = new URL(url);
|
|
30
|
+
domain = urlObj.hostname;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// If URL parsing fails, use the URL string itself for sorting
|
|
34
|
+
domain = url;
|
|
35
|
+
}
|
|
36
|
+
return { name, url, domain };
|
|
37
|
+
});
|
|
38
|
+
// Sort by domain, then by name
|
|
39
|
+
entries.sort((a, b) => {
|
|
40
|
+
const domainCompare = a.domain.localeCompare(b.domain);
|
|
41
|
+
if (domainCompare !== 0)
|
|
42
|
+
return domainCompare;
|
|
43
|
+
return a.name.localeCompare(b.name);
|
|
44
|
+
});
|
|
45
|
+
// Rebuild the urls object with sorted entries
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
sortedUrls[entry.name] = entry.url;
|
|
48
|
+
}
|
|
49
|
+
config.urls = sortedUrls;
|
|
50
|
+
}
|
|
21
51
|
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
22
52
|
}
|
|
23
53
|
// Add a new URL
|
|
@@ -114,7 +144,7 @@ export async function removeUrl(name) {
|
|
|
114
144
|
}
|
|
115
145
|
}
|
|
116
146
|
// Search and open URL in Chrome
|
|
117
|
-
export async function searchAndOpenUrl() {
|
|
147
|
+
export async function searchAndOpenUrl(suppress) {
|
|
118
148
|
try {
|
|
119
149
|
const config = readFullConfig();
|
|
120
150
|
if (!config.urls || Object.keys(config.urls).length === 0) {
|
|
@@ -135,8 +165,62 @@ export async function searchAndOpenUrl() {
|
|
|
135
165
|
// Open URL in Chrome (works on macOS, Linux, and Windows)
|
|
136
166
|
await $ `open -a "Google Chrome" ${selectedUrl}`;
|
|
137
167
|
console.log(chalk.green('✅ URL opened in Chrome'));
|
|
168
|
+
// Auto-dismiss popups if --suppress flag is enabled
|
|
169
|
+
if (suppress) {
|
|
170
|
+
console.log(chalk.blue('⏳ Waiting 1s before dismissing popup...'));
|
|
171
|
+
// Wait 1 second
|
|
172
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
173
|
+
// Use osascript to simulate Enter key press on macOS
|
|
174
|
+
await $ `osascript -e 'tell application "System Events" to keystroke return'`;
|
|
175
|
+
// Wait 1 second
|
|
176
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
177
|
+
// Use osascript to simulate Enter key press on macOS
|
|
178
|
+
await $ `osascript -e 'tell application "System Events" to keystroke return'`;
|
|
179
|
+
console.log(chalk.green('✅ Popup dismissed with Enter key'));
|
|
180
|
+
}
|
|
138
181
|
}
|
|
139
182
|
catch (error) {
|
|
140
183
|
console.error(chalk.red('Error opening URL:'), error);
|
|
141
184
|
}
|
|
142
185
|
}
|
|
186
|
+
// Open URL group in a new Chrome window
|
|
187
|
+
export async function openUrlGroup() {
|
|
188
|
+
try {
|
|
189
|
+
const config = readFullConfig();
|
|
190
|
+
if (!config.urlGroups || Object.keys(config.urlGroups).length === 0) {
|
|
191
|
+
console.log(chalk.yellow('⚠️ No URL groups found in configuration.'));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const groupNames = Object.keys(config.urlGroups);
|
|
195
|
+
const answer = await inquirer.prompt([
|
|
196
|
+
{
|
|
197
|
+
type: 'list',
|
|
198
|
+
name: 'selectedGroup',
|
|
199
|
+
message: 'Select a URL group to open:',
|
|
200
|
+
choices: groupNames,
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
const selectedGroupName = answer.selectedGroup;
|
|
204
|
+
const urls = config.urlGroups[selectedGroupName];
|
|
205
|
+
if (!urls || urls.length === 0) {
|
|
206
|
+
console.log(chalk.yellow(`⚠️ No URLs found in group "${selectedGroupName}".`));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
console.log(chalk.blue(`🌐 Opening ${urls.length} URLs from group "${selectedGroupName}"...`));
|
|
210
|
+
// Open all URLs in a new Chrome window
|
|
211
|
+
// First URL opens in a new window
|
|
212
|
+
await $ `open -na "Google Chrome" --args --new-window ${urls[0]}`;
|
|
213
|
+
// Add a small delay to ensure Chrome window is ready
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
215
|
+
// Open remaining URLs as tabs in the same window
|
|
216
|
+
for (let i = 1; i < urls.length; i++) {
|
|
217
|
+
await $ `open -a "Google Chrome" ${urls[i]}`;
|
|
218
|
+
// Small delay between opening tabs to ensure they all load properly
|
|
219
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
220
|
+
}
|
|
221
|
+
console.log(chalk.green(`✅ Opened ${urls.length} URLs in Chrome`));
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
console.error(chalk.red('Error opening URL group:'), error);
|
|
225
|
+
}
|
|
226
|
+
}
|
package/dist/hsh.js
CHANGED
|
@@ -6,7 +6,7 @@ import { getPackageJson } from './util.js';
|
|
|
6
6
|
import { openIDE } from './commands/ide/index.js';
|
|
7
7
|
import { cloudLogin, cloudScp } from './commands/cloud.js';
|
|
8
8
|
import { syncMcpServers } from './commands/mcp.js';
|
|
9
|
-
import { addUrl, removeUrl, searchAndOpenUrl } from './commands/url.js';
|
|
9
|
+
import { addUrl, openUrlGroup, removeUrl, searchAndOpenUrl } from './commands/url.js';
|
|
10
10
|
const packageJson = getPackageJson();
|
|
11
11
|
const program = new Command();
|
|
12
12
|
program.usage('<command> [options]');
|
|
@@ -134,7 +134,14 @@ urlCommand
|
|
|
134
134
|
urlCommand
|
|
135
135
|
.command('search')
|
|
136
136
|
.description('Search and open a URL bookmark in Chrome')
|
|
137
|
+
.option('--suppress', 'Auto-dismiss popups by simulating Enter key after 1s')
|
|
138
|
+
.action(async (options) => {
|
|
139
|
+
await searchAndOpenUrl(options.suppress);
|
|
140
|
+
});
|
|
141
|
+
urlCommand
|
|
142
|
+
.command('group')
|
|
143
|
+
.description('Select and open a URL group in a new Chrome window')
|
|
137
144
|
.action(async () => {
|
|
138
|
-
await
|
|
145
|
+
await openUrlGroup();
|
|
139
146
|
});
|
|
140
147
|
program.parse();
|
package/dist/types/index.d.ts
CHANGED
package/package.json
CHANGED
package/src/commands/url.ts
CHANGED
|
@@ -23,6 +23,39 @@ function readFullConfig(): HshConfig {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function writeConfig(config: HshConfig): void {
|
|
26
|
+
// Sort URLs by domain before writing
|
|
27
|
+
if (config.urls) {
|
|
28
|
+
const sortedUrls: Record<string, string> = {};
|
|
29
|
+
|
|
30
|
+
// Create entries with extracted domains for sorting
|
|
31
|
+
const entries = Object.entries(config.urls).map(([name, url]) => {
|
|
32
|
+
// Extract domain from URL
|
|
33
|
+
let domain = '';
|
|
34
|
+
try {
|
|
35
|
+
const urlObj = new URL(url);
|
|
36
|
+
domain = urlObj.hostname;
|
|
37
|
+
} catch {
|
|
38
|
+
// If URL parsing fails, use the URL string itself for sorting
|
|
39
|
+
domain = url;
|
|
40
|
+
}
|
|
41
|
+
return { name, url, domain };
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Sort by domain, then by name
|
|
45
|
+
entries.sort((a, b) => {
|
|
46
|
+
const domainCompare = a.domain.localeCompare(b.domain);
|
|
47
|
+
if (domainCompare !== 0) return domainCompare;
|
|
48
|
+
return a.name.localeCompare(b.name);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Rebuild the urls object with sorted entries
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
sortedUrls[entry.name] = entry.url;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
config.urls = sortedUrls;
|
|
57
|
+
}
|
|
58
|
+
|
|
26
59
|
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
27
60
|
}
|
|
28
61
|
|
|
@@ -135,7 +168,7 @@ export async function removeUrl(name?: string): Promise<void> {
|
|
|
135
168
|
}
|
|
136
169
|
|
|
137
170
|
// Search and open URL in Chrome
|
|
138
|
-
export async function searchAndOpenUrl(): Promise<void> {
|
|
171
|
+
export async function searchAndOpenUrl(suppress?: boolean): Promise<void> {
|
|
139
172
|
try {
|
|
140
173
|
const config = readFullConfig();
|
|
141
174
|
|
|
@@ -160,7 +193,74 @@ export async function searchAndOpenUrl(): Promise<void> {
|
|
|
160
193
|
// Open URL in Chrome (works on macOS, Linux, and Windows)
|
|
161
194
|
await $`open -a "Google Chrome" ${selectedUrl}`;
|
|
162
195
|
console.log(chalk.green('✅ URL opened in Chrome'));
|
|
196
|
+
|
|
197
|
+
// Auto-dismiss popups if --suppress flag is enabled
|
|
198
|
+
if (suppress) {
|
|
199
|
+
console.log(chalk.blue('⏳ Waiting 1s before dismissing popup...'));
|
|
200
|
+
// Wait 1 second
|
|
201
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
202
|
+
|
|
203
|
+
// Use osascript to simulate Enter key press on macOS
|
|
204
|
+
await $`osascript -e 'tell application "System Events" to keystroke return'`;
|
|
205
|
+
|
|
206
|
+
// Wait 1 second
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
208
|
+
|
|
209
|
+
// Use osascript to simulate Enter key press on macOS
|
|
210
|
+
await $`osascript -e 'tell application "System Events" to keystroke return'`;
|
|
211
|
+
console.log(chalk.green('✅ Popup dismissed with Enter key'));
|
|
212
|
+
}
|
|
163
213
|
} catch (error) {
|
|
164
214
|
console.error(chalk.red('Error opening URL:'), error);
|
|
165
215
|
}
|
|
166
216
|
}
|
|
217
|
+
|
|
218
|
+
// Open URL group in a new Chrome window
|
|
219
|
+
export async function openUrlGroup(): Promise<void> {
|
|
220
|
+
try {
|
|
221
|
+
const config = readFullConfig();
|
|
222
|
+
|
|
223
|
+
if (!config.urlGroups || Object.keys(config.urlGroups).length === 0) {
|
|
224
|
+
console.log(chalk.yellow('⚠️ No URL groups found in configuration.'));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const groupNames = Object.keys(config.urlGroups);
|
|
229
|
+
const answer = await inquirer.prompt([
|
|
230
|
+
{
|
|
231
|
+
type: 'list',
|
|
232
|
+
name: 'selectedGroup',
|
|
233
|
+
message: 'Select a URL group to open:',
|
|
234
|
+
choices: groupNames,
|
|
235
|
+
},
|
|
236
|
+
]);
|
|
237
|
+
|
|
238
|
+
const selectedGroupName = answer.selectedGroup;
|
|
239
|
+
const urls = config.urlGroups[selectedGroupName];
|
|
240
|
+
|
|
241
|
+
if (!urls || urls.length === 0) {
|
|
242
|
+
console.log(chalk.yellow(`⚠️ No URLs found in group "${selectedGroupName}".`));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log(chalk.blue(`🌐 Opening ${urls.length} URLs from group "${selectedGroupName}"...`));
|
|
247
|
+
|
|
248
|
+
// Open all URLs in a new Chrome window
|
|
249
|
+
// First URL opens in a new window
|
|
250
|
+
await $`open -na "Google Chrome" --args --new-window ${urls[0]}`;
|
|
251
|
+
|
|
252
|
+
// Add a small delay to ensure Chrome window is ready
|
|
253
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
254
|
+
|
|
255
|
+
// Open remaining URLs as tabs in the same window
|
|
256
|
+
for (let i = 1; i < urls.length; i++) {
|
|
257
|
+
await $`open -a "Google Chrome" ${urls[i]}`;
|
|
258
|
+
// Small delay between opening tabs to ensure they all load properly
|
|
259
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
console.log(chalk.green(`✅ Opened ${urls.length} URLs in Chrome`));
|
|
263
|
+
} catch (error) {
|
|
264
|
+
console.error(chalk.red('Error opening URL group:'), error);
|
|
265
|
+
}
|
|
266
|
+
}
|
package/src/hsh.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { getPackageJson } from './util.js';
|
|
|
7
7
|
import { openIDE } from './commands/ide/index.js';
|
|
8
8
|
import { cloudLogin, cloudScp } from './commands/cloud.js';
|
|
9
9
|
import { syncMcpServers } from './commands/mcp.js';
|
|
10
|
-
import { addUrl, removeUrl, searchAndOpenUrl } from './commands/url.js';
|
|
10
|
+
import { addUrl, openUrlGroup, removeUrl, searchAndOpenUrl } from './commands/url.js';
|
|
11
11
|
|
|
12
12
|
const packageJson = getPackageJson();
|
|
13
13
|
|
|
@@ -159,8 +159,16 @@ urlCommand
|
|
|
159
159
|
urlCommand
|
|
160
160
|
.command('search')
|
|
161
161
|
.description('Search and open a URL bookmark in Chrome')
|
|
162
|
+
.option('--suppress', 'Auto-dismiss popups by simulating Enter key after 1s')
|
|
163
|
+
.action(async (options: { suppress?: boolean }) => {
|
|
164
|
+
await searchAndOpenUrl(options.suppress);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
urlCommand
|
|
168
|
+
.command('group')
|
|
169
|
+
.description('Select and open a URL group in a new Chrome window')
|
|
162
170
|
.action(async () => {
|
|
163
|
-
await
|
|
171
|
+
await openUrlGroup();
|
|
164
172
|
});
|
|
165
173
|
|
|
166
174
|
program.parse();
|