@kud/foxhop-cli 1.0.2 → 1.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.
- package/dist/cli.js +120 -17
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { defineCommand, runMain } from "citty";
|
|
5
5
|
import { spawn } from "child_process";
|
|
6
|
+
import { existsSync as existsSync3 } from "fs";
|
|
6
7
|
|
|
7
8
|
// src/config.ts
|
|
8
9
|
import { mkdirSync, readFileSync, writeFileSync, existsSync } from "fs";
|
|
@@ -52,6 +53,10 @@ var SCHEMA = {
|
|
|
52
53
|
enum: ["recent", "first", "pinned"],
|
|
53
54
|
default: "recent",
|
|
54
55
|
description: "Which tab to focus when several match"
|
|
56
|
+
},
|
|
57
|
+
favorite: {
|
|
58
|
+
type: "boolean",
|
|
59
|
+
description: "Pin this target to the top of the list"
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
62
|
}
|
|
@@ -112,6 +117,34 @@ var removeTarget = (name) => {
|
|
|
112
117
|
if (removed) writeConfig({ targets: filtered });
|
|
113
118
|
return { targets: filtered, removed };
|
|
114
119
|
};
|
|
120
|
+
var toggleFavorite = (name) => {
|
|
121
|
+
const { targets } = readConfig();
|
|
122
|
+
let favorite = false;
|
|
123
|
+
let found = false;
|
|
124
|
+
const next = targets.map((target) => {
|
|
125
|
+
if (target.name !== name) return target;
|
|
126
|
+
found = true;
|
|
127
|
+
favorite = !target.favorite;
|
|
128
|
+
const { favorite: _was, ...rest } = target;
|
|
129
|
+
return favorite ? { ...rest, favorite: true } : rest;
|
|
130
|
+
});
|
|
131
|
+
if (found) writeConfig({ targets: next });
|
|
132
|
+
return { favorite, found };
|
|
133
|
+
};
|
|
134
|
+
var deriveTarget = (url) => {
|
|
135
|
+
let host = url.trim();
|
|
136
|
+
try {
|
|
137
|
+
host = new URL(url).hostname;
|
|
138
|
+
} catch {
|
|
139
|
+
host = url.replace(/^[a-z]+:\/\//i, "").split("/")[0] || url;
|
|
140
|
+
}
|
|
141
|
+
const labels = host.split(".").filter(Boolean);
|
|
142
|
+
const generic = /* @__PURE__ */ new Set(["www", "app", "web", "m", "my", "go"]);
|
|
143
|
+
const candidates = labels.length > 1 ? labels.slice(0, -1) : labels;
|
|
144
|
+
const name = (candidates.find((label) => !generic.has(label)) ?? candidates[0] ?? host).toLowerCase();
|
|
145
|
+
const title = name.charAt(0).toUpperCase() + name.slice(1);
|
|
146
|
+
return { name, match: host, title };
|
|
147
|
+
};
|
|
115
148
|
|
|
116
149
|
// src/client.ts
|
|
117
150
|
import net from "net";
|
|
@@ -213,7 +246,7 @@ var scriptBody = (node, cli, target) => {
|
|
|
213
246
|
# @raycast.schemaVersion 1
|
|
214
247
|
# @raycast.title Focus ${title}
|
|
215
248
|
# @raycast.mode silent
|
|
216
|
-
# @raycast.packageName
|
|
249
|
+
# @raycast.packageName Fox Hop
|
|
217
250
|
# @raycast.icon ${ICON_FILE}
|
|
218
251
|
|
|
219
252
|
# Documentation:
|
|
@@ -245,6 +278,14 @@ var sync = (node, cli, dir = defaultScriptsDir()) => {
|
|
|
245
278
|
}
|
|
246
279
|
return { dir, written: targets.length, removed: removed.length };
|
|
247
280
|
};
|
|
281
|
+
var clearScripts = (dir = defaultScriptsDir()) => {
|
|
282
|
+
if (!existsSync2(dir)) return { dir, written: 0, removed: 0 };
|
|
283
|
+
const removed = readdirSync(dir).filter((file) => file.startsWith("focus-") && file.endsWith(".sh")).filter((file) => isGenerated(join4(dir, file)));
|
|
284
|
+
for (const file of removed) rmSync(join4(dir, file));
|
|
285
|
+
const icon = join4(dir, ICON_FILE);
|
|
286
|
+
if (existsSync2(icon)) rmSync(icon);
|
|
287
|
+
return { dir, written: 0, removed: removed.length };
|
|
288
|
+
};
|
|
248
289
|
|
|
249
290
|
// src/cli.ts
|
|
250
291
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -260,6 +301,11 @@ var runOpen = (args) => {
|
|
|
260
301
|
};
|
|
261
302
|
var foreground = () => runOpen(["-a", browserApp()]);
|
|
262
303
|
var openUrl = (url) => runOpen([url]);
|
|
304
|
+
var autoSync = () => {
|
|
305
|
+
if (existsSync3(defaultScriptsDir())) {
|
|
306
|
+
sync(process.execPath, fileURLToPath2(import.meta.url));
|
|
307
|
+
}
|
|
308
|
+
};
|
|
263
309
|
var focus = defineCommand({
|
|
264
310
|
meta: {
|
|
265
311
|
name: "focus",
|
|
@@ -344,8 +390,13 @@ var list = defineCommand({
|
|
|
344
390
|
);
|
|
345
391
|
return;
|
|
346
392
|
}
|
|
347
|
-
|
|
348
|
-
|
|
393
|
+
const ordered = [
|
|
394
|
+
...targets.filter((target) => target.favorite),
|
|
395
|
+
...targets.filter((target) => !target.favorite)
|
|
396
|
+
];
|
|
397
|
+
for (const target of ordered) {
|
|
398
|
+
const star = target.favorite ? "\u2605 " : " ";
|
|
399
|
+
console.log(`${star}${target.name.padEnd(16)} ${target.match}`);
|
|
349
400
|
}
|
|
350
401
|
}
|
|
351
402
|
});
|
|
@@ -398,9 +449,24 @@ var syncCommand = defineCommand({
|
|
|
398
449
|
type: "string",
|
|
399
450
|
description: `Output directory (default: ${defaultScriptsDir()})`
|
|
400
451
|
},
|
|
452
|
+
clean: {
|
|
453
|
+
type: "boolean",
|
|
454
|
+
description: "Remove all generated scripts instead of writing them"
|
|
455
|
+
},
|
|
401
456
|
json: { type: "boolean", description: "Output the result as JSON" }
|
|
402
457
|
},
|
|
403
458
|
run: ({ args }) => {
|
|
459
|
+
if (args.clean) {
|
|
460
|
+
const cleared = clearScripts(args.dir);
|
|
461
|
+
if (args.json) {
|
|
462
|
+
process.stdout.write(JSON.stringify(cleared) + "\n");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
console.log(
|
|
466
|
+
`foxhop: removed ${cleared.removed} script(s) from ${cleared.dir}`
|
|
467
|
+
);
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
404
470
|
const result = sync(
|
|
405
471
|
process.execPath,
|
|
406
472
|
fileURLToPath2(import.meta.url),
|
|
@@ -419,20 +485,25 @@ var syncCommand = defineCommand({
|
|
|
419
485
|
}
|
|
420
486
|
});
|
|
421
487
|
var add = defineCommand({
|
|
422
|
-
meta: {
|
|
488
|
+
meta: {
|
|
489
|
+
name: "add",
|
|
490
|
+
description: "Add or update a target \u2014 name/match/title derive from the URL"
|
|
491
|
+
},
|
|
423
492
|
args: {
|
|
424
|
-
|
|
493
|
+
url: {
|
|
425
494
|
type: "positional",
|
|
426
495
|
required: true,
|
|
427
|
-
description: "
|
|
496
|
+
description: "URL of the tab (e.g. https://gemini.google.com)"
|
|
497
|
+
},
|
|
498
|
+
name: {
|
|
499
|
+
type: "string",
|
|
500
|
+
description: "Override the derived id (used by `foxhop focus <name>`)"
|
|
428
501
|
},
|
|
502
|
+
title: { type: "string", description: "Override the derived label" },
|
|
429
503
|
match: {
|
|
430
504
|
type: "string",
|
|
431
|
-
|
|
432
|
-
description: "Substring matched against tab URLs"
|
|
505
|
+
description: "Override the derived match (default: the URL hostname)"
|
|
433
506
|
},
|
|
434
|
-
url: { type: "string", description: "URL opened when no tab matches" },
|
|
435
|
-
title: { type: "string", description: "Human-friendly label" },
|
|
436
507
|
strategy: {
|
|
437
508
|
type: "string",
|
|
438
509
|
description: "hostname | prefix | exact | search"
|
|
@@ -440,18 +511,25 @@ var add = defineCommand({
|
|
|
440
511
|
pick: {
|
|
441
512
|
type: "string",
|
|
442
513
|
description: "recent | first | pinned (which tab when several match)"
|
|
443
|
-
}
|
|
514
|
+
},
|
|
515
|
+
favorite: { type: "boolean", description: "Pin to the top of the list" }
|
|
444
516
|
},
|
|
445
517
|
run: ({ args }) => {
|
|
518
|
+
const url = String(args.url);
|
|
519
|
+
const derived = deriveTarget(url);
|
|
520
|
+
const name = args.name ?? derived.name;
|
|
521
|
+
const existing = findTarget(readConfig(), name);
|
|
446
522
|
upsertTarget({
|
|
447
|
-
name
|
|
448
|
-
match:
|
|
449
|
-
url
|
|
450
|
-
title: args.title,
|
|
523
|
+
name,
|
|
524
|
+
match: args.match ?? derived.match,
|
|
525
|
+
url,
|
|
526
|
+
title: args.title ?? derived.title,
|
|
451
527
|
strategy: args.strategy,
|
|
452
|
-
pick: args.pick
|
|
528
|
+
pick: args.pick,
|
|
529
|
+
favorite: args.favorite || existing?.favorite ? true : void 0
|
|
453
530
|
});
|
|
454
|
-
console.log(`foxhop: saved "${
|
|
531
|
+
console.log(`foxhop: saved "${name}"`);
|
|
532
|
+
autoSync();
|
|
455
533
|
}
|
|
456
534
|
});
|
|
457
535
|
var remove = defineCommand({
|
|
@@ -470,6 +548,30 @@ var remove = defineCommand({
|
|
|
470
548
|
process.exit(1);
|
|
471
549
|
}
|
|
472
550
|
console.log(`foxhop: removed "${args.name}"`);
|
|
551
|
+
autoSync();
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
var fav = defineCommand({
|
|
555
|
+
meta: {
|
|
556
|
+
name: "fav",
|
|
557
|
+
description: "Toggle a target's favourite (pins it to the top of the list)"
|
|
558
|
+
},
|
|
559
|
+
args: {
|
|
560
|
+
name: {
|
|
561
|
+
type: "positional",
|
|
562
|
+
required: true,
|
|
563
|
+
description: "Target id to toggle"
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
run: ({ args }) => {
|
|
567
|
+
const { favorite, found } = toggleFavorite(String(args.name));
|
|
568
|
+
if (!found) {
|
|
569
|
+
console.error(`foxhop: no target named "${args.name}"`);
|
|
570
|
+
process.exit(1);
|
|
571
|
+
}
|
|
572
|
+
console.log(
|
|
573
|
+
`foxhop: "${args.name}" ${favorite ? "favourited \u2605" : "unfavourited"}`
|
|
574
|
+
);
|
|
473
575
|
}
|
|
474
576
|
});
|
|
475
577
|
var NAME = "foxhop";
|
|
@@ -479,6 +581,7 @@ var subCommands = {
|
|
|
479
581
|
tabs,
|
|
480
582
|
add,
|
|
481
583
|
remove,
|
|
584
|
+
fav,
|
|
482
585
|
init,
|
|
483
586
|
sync: syncCommand,
|
|
484
587
|
install: installCommand
|