@nevermorelove/ompp 0.3.2 → 0.4.1
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 +4 -0
- package/ompp.js +120 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,10 @@ ompp list print mode names
|
|
|
32
32
|
ompp pentest --dry-run show the omp command line instead of running it
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
In the picker, `r` renames the highlighted mode and `d` deletes it (after a
|
|
36
|
+
confirmation). The picker reopens after either, so a mispress costs nothing:
|
|
37
|
+
cancel the rename or keep the mode, and you are back in the list.
|
|
38
|
+
|
|
35
39
|
Before launch it prints one line to stderr, `[ompp] mode: pentest`, so you always know where you are.
|
|
36
40
|
|
|
37
41
|
Modes are read from two places, and same-named modes from the first win:
|
package/ompp.js
CHANGED
|
@@ -226,6 +226,7 @@ function usage() {
|
|
|
226
226
|
|
|
227
227
|
Usage:
|
|
228
228
|
ompp pick a mode interactively, then launch omp
|
|
229
|
+
(r: rename, d: delete on the highlighted mode)
|
|
229
230
|
ompp <mode> [args...] launch omp in a mode; everything after <mode>
|
|
230
231
|
is passed to omp unchanged and wins over the mode
|
|
231
232
|
ompp create <name> create a new mode with placeholder files
|
|
@@ -343,44 +344,129 @@ function createMode(name) {
|
|
|
343
344
|
return 0;
|
|
344
345
|
}
|
|
345
346
|
|
|
347
|
+
function renameMode(mode, newName) {
|
|
348
|
+
if (!newName || !isValidModeName(newName)) {
|
|
349
|
+
console.error(`[ompp] "${newName}" is not a valid mode name.`);
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
if (RESERVED_NAMES.includes(newName)) {
|
|
353
|
+
console.error(`[ompp] "${newName}" is reserved for ompp commands.`);
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
const from = modeDirOf(mode.name, mode.source);
|
|
357
|
+
const to = modeDirOf(newName, mode.source);
|
|
358
|
+
if (fs.existsSync(to)) {
|
|
359
|
+
console.error(`[ompp] mode "${newName}" already exists.`);
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
fs.renameSync(from, to);
|
|
363
|
+
console.error(`[ompp] renamed "${mode.name}" to "${newName}"`);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function deleteMode(mode) {
|
|
368
|
+
const dir = modeDirOf(mode.name, mode.source);
|
|
369
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
370
|
+
console.error(`[ompp] deleted mode "${mode.name}"`);
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
|
|
346
374
|
const CREATE_OPTION = "__create__";
|
|
347
375
|
|
|
348
376
|
function isValidModeName(name) {
|
|
349
377
|
return /^[a-z0-9][a-z0-9-]*$/.test(name);
|
|
350
378
|
}
|
|
351
379
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
if (chosen === CREATE_OPTION) {
|
|
367
|
-
const name = await text({
|
|
368
|
-
message: "New mode name",
|
|
369
|
-
validate: (v) => {
|
|
370
|
-
if (!v || !isValidModeName(v)) {
|
|
371
|
-
return "Lowercase letters, digits, and dashes only";
|
|
372
|
-
}
|
|
373
|
-
if (RESERVED_NAMES.includes(v)) return `"${v}" is reserved`;
|
|
374
|
-
return undefined;
|
|
375
|
-
},
|
|
380
|
+
// The interactive picker. Receives mode objects ({name, source}), returns
|
|
381
|
+
// the picked mode object, or {create: <name>} for the create flow.
|
|
382
|
+
// r renames and d deletes the highlighted mode; both re-render the picker.
|
|
383
|
+
async function pickMode(modes) {
|
|
384
|
+
const { select, text, confirm, isCancel, cancel } = require("@clack/prompts");
|
|
385
|
+
for (;;) {
|
|
386
|
+
const options = [
|
|
387
|
+
...modes.map((m) => ({ value: m, label: m.name })),
|
|
388
|
+
{ value: CREATE_OPTION, label: "Create a new mode +" },
|
|
389
|
+
];
|
|
390
|
+
const chosen = await select({
|
|
391
|
+
message: "Pick a mode",
|
|
392
|
+
options,
|
|
376
393
|
});
|
|
377
|
-
|
|
394
|
+
|
|
395
|
+
if (isCancel(chosen)) {
|
|
378
396
|
cancel("Cancelled");
|
|
379
397
|
process.exit(130);
|
|
380
398
|
}
|
|
381
|
-
|
|
399
|
+
|
|
400
|
+
if (chosen === CREATE_OPTION) {
|
|
401
|
+
const name = await text({
|
|
402
|
+
message: "New mode name",
|
|
403
|
+
validate: (v) => {
|
|
404
|
+
if (!v || !isValidModeName(v)) {
|
|
405
|
+
return "Lowercase letters, digits, and dashes only";
|
|
406
|
+
}
|
|
407
|
+
if (RESERVED_NAMES.includes(v)) return `"${v}" is reserved`;
|
|
408
|
+
return undefined;
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
if (isCancel(name)) {
|
|
412
|
+
cancel("Cancelled");
|
|
413
|
+
process.exit(130);
|
|
414
|
+
}
|
|
415
|
+
return { create: name };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Second step: what to do with the picked mode. This replaces the
|
|
419
|
+
// previous r/d hotkey hack (process.stdin keypress rewrite) which left
|
|
420
|
+
// Windows terminals in raw mode and hung randomly.
|
|
421
|
+
const action = await select({
|
|
422
|
+
message: `Mode "${chosen.name}" — what next?`,
|
|
423
|
+
options: [
|
|
424
|
+
{ value: "launch", label: "Launch" },
|
|
425
|
+
{ value: "rename", label: "Rename" },
|
|
426
|
+
{ value: "delete", label: "Delete" },
|
|
427
|
+
{ value: "back", label: "Back" },
|
|
428
|
+
],
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
if (isCancel(action) || action === "back") continue;
|
|
432
|
+
if (action === "launch") return chosen;
|
|
433
|
+
|
|
434
|
+
if (action === "rename") {
|
|
435
|
+
const newName = await text({
|
|
436
|
+
message: `Rename "${chosen.name}" to`,
|
|
437
|
+
validate: (v) => {
|
|
438
|
+
if (!v || !isValidModeName(v)) {
|
|
439
|
+
return "Lowercase letters, digits, and dashes only";
|
|
440
|
+
}
|
|
441
|
+
if (RESERVED_NAMES.includes(v)) return `"${v}" is reserved`;
|
|
442
|
+
if (modes.some((m) => m.name === v)) return `"${v}" already exists`;
|
|
443
|
+
return undefined;
|
|
444
|
+
},
|
|
445
|
+
});
|
|
446
|
+
if (!isCancel(newName) && newName !== chosen.name) {
|
|
447
|
+
if (renameMode(chosen, newName)) chosen.name = newName;
|
|
448
|
+
} else {
|
|
449
|
+
cancel("Rename cancelled");
|
|
450
|
+
}
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (action === "delete") {
|
|
455
|
+
const sure = await confirm({
|
|
456
|
+
message: `Delete "${chosen.name}"? This removes its folder.`,
|
|
457
|
+
active: "Delete",
|
|
458
|
+
inactive: "Keep",
|
|
459
|
+
});
|
|
460
|
+
if (!isCancel(sure) && sure) {
|
|
461
|
+
deleteMode(chosen);
|
|
462
|
+
const idx = modes.findIndex((m) => m.name === chosen.name);
|
|
463
|
+
if (idx !== -1) modes.splice(idx, 1);
|
|
464
|
+
} else {
|
|
465
|
+
cancel("Delete cancelled");
|
|
466
|
+
}
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
382
469
|
}
|
|
383
|
-
return chosen;
|
|
384
470
|
}
|
|
385
471
|
|
|
386
472
|
// Non-TTY stdin: clack needs an interactive terminal, so numbered input.
|
|
@@ -521,16 +607,20 @@ async function main() {
|
|
|
521
607
|
|
|
522
608
|
if (!mode) {
|
|
523
609
|
try {
|
|
524
|
-
|
|
525
|
-
? await pickMode(
|
|
610
|
+
let picked = process.stdin.isTTY
|
|
611
|
+
? await pickMode(modes)
|
|
526
612
|
: await pickModePiped(modeNames);
|
|
613
|
+
if (typeof picked === "string") {
|
|
614
|
+
// The piped picker returns a name; normalize to the mode object.
|
|
615
|
+
picked = modes.find((m) => m.name === picked);
|
|
616
|
+
}
|
|
527
617
|
if (picked && typeof picked === "object" && picked.create) {
|
|
528
618
|
// Scaffold and stop: the mode is all placeholders, launching it
|
|
529
619
|
// now would run an unconfigured mode. The user fills it in and
|
|
530
620
|
// launches when ready.
|
|
531
621
|
return createMode(picked.create);
|
|
532
622
|
} else {
|
|
533
|
-
mode =
|
|
623
|
+
mode = picked;
|
|
534
624
|
}
|
|
535
625
|
} catch (err) {
|
|
536
626
|
console.error(`[ompp] ${err.message}`);
|