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 CHANGED
@@ -164,3 +164,4 @@ yarn dev
164
164
  ## License
165
165
 
166
166
  MIT
167
+
@@ -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>;
@@ -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 searchAndOpenUrl();
145
+ await openUrlGroup();
139
146
  });
140
147
  program.parse();
@@ -21,6 +21,9 @@ export interface HshConfig {
21
21
  urls?: {
22
22
  [name: string]: string;
23
23
  };
24
+ urlGroups?: {
25
+ [groupName: string]: string[];
26
+ };
24
27
  }
25
28
  export type Environment = 'dev' | 'staging' | 'prod';
26
29
  export interface ScpOptions {
@@ -238,3 +238,4 @@ Potential improvements for future versions:
238
238
  - Recent projects tracking and prioritization
239
239
  - Favorites/bookmarks system
240
240
  - Project metadata display (last opened, git branch, etc.)
241
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hsh19900502",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "index.js",
@@ -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 searchAndOpenUrl();
171
+ await openUrlGroup();
164
172
  });
165
173
 
166
174
  program.parse();
@@ -26,6 +26,9 @@ export interface HshConfig {
26
26
  urls?: {
27
27
  [name: string]: string;
28
28
  };
29
+ urlGroups?: {
30
+ [groupName: string]: string[];
31
+ };
29
32
  }
30
33
 
31
34
  export type Environment = 'dev' | 'staging' | 'prod';