@krtclcdy/tersio 2.3.0 → 2.4.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/README.md +1 -1
- package/package.json +5 -2
- package/tersio.js +162 -65
package/README.md
CHANGED
|
@@ -160,7 +160,7 @@ The installer writes `<file>.bak` before replacing an extension source; the upda
|
|
|
160
160
|
## Requirements
|
|
161
161
|
|
|
162
162
|
- [OMP](https://github.com/can1357/oh-my-pi)
|
|
163
|
-
- Node.js
|
|
163
|
+
- Node.js 20.12+ with npm
|
|
164
164
|
|
|
165
165
|
Windows/WSL have separate OMP homes — install from the environment where OMP runs. Inside WSL, `command -v npm` must resolve to a Linux path, not `/mnt/c/`.
|
|
166
166
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krtclcdy/tersio",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "✂️ Token-saving OMP add-ons: terse Caveman replies, compact RTK shell output, lean Ponytail code calls — one-command combo presets.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"omp",
|
|
@@ -119,11 +119,14 @@
|
|
|
119
119
|
"test": "tsx --test test/*.test.ts test/*/*.test.ts"
|
|
120
120
|
},
|
|
121
121
|
"engines": {
|
|
122
|
-
"node": ">=
|
|
122
|
+
"node": ">=20.12.0"
|
|
123
123
|
},
|
|
124
124
|
"devDependencies": {
|
|
125
125
|
"@types/node": "^26.4.1",
|
|
126
126
|
"tsx": "^4.23.13",
|
|
127
127
|
"typescript": "^7.0.2"
|
|
128
|
+
},
|
|
129
|
+
"dependencies": {
|
|
130
|
+
"@clack/prompts": "^1.8.0"
|
|
128
131
|
}
|
|
129
132
|
}
|
package/tersio.js
CHANGED
|
@@ -10,6 +10,7 @@ import readline from 'node:readline';
|
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import { promisify } from 'node:util';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
|
+
import { cancel as clackCancel, confirm as clackConfirm, select as clackSelect, spinner as clackSpinner, tasks as clackTasks } from '@clack/prompts';
|
|
13
14
|
import { CAVEMAN_REMOTE_RULE, RTK_RELEASE_API, fetchJson, findFile, httpsGet, httpsDownload, sha256File, parseChecksum, readTextIfExists, rtkPlatformSpec, } from './extensions/lib/utils.js';
|
|
14
15
|
const IS_WINDOWS = process.platform === 'win32';
|
|
15
16
|
const RTK_BINARY_NAME = IS_WINDOWS ? 'rtk.exe' : 'rtk';
|
|
@@ -150,6 +151,9 @@ async function execP(cmd, args, opts = {}) {
|
|
|
150
151
|
...opts,
|
|
151
152
|
});
|
|
152
153
|
}
|
|
154
|
+
async function execNetwork(label, cmd, args, opts = {}) {
|
|
155
|
+
return withInteractiveSpinner(label, () => execP(cmd, args, opts));
|
|
156
|
+
}
|
|
153
157
|
async function writeIfChanged(dest, content, options = {}) {
|
|
154
158
|
const existing = await readTextIfExists(dest);
|
|
155
159
|
if (existing === content) {
|
|
@@ -332,7 +336,7 @@ async function stepPonytail(pluginsDir, userDir, options) {
|
|
|
332
336
|
else {
|
|
333
337
|
// Try omp plugin install first
|
|
334
338
|
try {
|
|
335
|
-
await
|
|
339
|
+
await execNetwork('Installing Ponytail plugin', OMP_BIN, ['plugin', 'install', PONYTAIL_GITHUB_SPEC], { cwd: pluginsDir });
|
|
336
340
|
console.log(' [ok] omp plugin install ran');
|
|
337
341
|
}
|
|
338
342
|
catch (e) {
|
|
@@ -340,7 +344,7 @@ async function stepPonytail(pluginsDir, userDir, options) {
|
|
|
340
344
|
}
|
|
341
345
|
if (options.reinstall) {
|
|
342
346
|
try {
|
|
343
|
-
await
|
|
347
|
+
await execNetwork('Refreshing Ponytail package', 'npm', ['install', PONYTAIL_NPM_SPEC, '--save', '--no-audit', '--no-fund'], { cwd: pluginsDir, timeout: 120000 });
|
|
344
348
|
console.log(' [ok] Ponytail refreshed');
|
|
345
349
|
}
|
|
346
350
|
catch (e) {
|
|
@@ -354,12 +358,12 @@ async function stepPonytail(pluginsDir, userDir, options) {
|
|
|
354
358
|
if (!ponytailExtExists) {
|
|
355
359
|
console.log(' [info] pi-extension/index.js not found after omp plugin install — trying npm/bun install...');
|
|
356
360
|
try {
|
|
357
|
-
await
|
|
361
|
+
await execNetwork('Installing Ponytail dependencies', 'npm', ['install'], { cwd: pluginsDir, timeout: 120000 });
|
|
358
362
|
console.log(' [ok] npm install completed');
|
|
359
363
|
}
|
|
360
364
|
catch {
|
|
361
365
|
try {
|
|
362
|
-
await
|
|
366
|
+
await execNetwork('Installing Ponytail dependencies', 'bun', ['install'], { cwd: pluginsDir, timeout: 120000 });
|
|
363
367
|
console.log(' [ok] bun install completed');
|
|
364
368
|
}
|
|
365
369
|
catch (e2) {
|
|
@@ -375,7 +379,7 @@ async function stepPonytail(pluginsDir, userDir, options) {
|
|
|
375
379
|
try {
|
|
376
380
|
const dest = path.join(pluginsDir, 'node_modules', '@dietrichgebert', 'ponytail');
|
|
377
381
|
await fs.mkdir(path.dirname(dest), { recursive: true });
|
|
378
|
-
await
|
|
382
|
+
await execNetwork('Cloning Ponytail repository', 'git', ['clone', '--depth', '1', 'https://github.com/DietrichGebert/ponytail.git', dest], { timeout: 180000 });
|
|
379
383
|
console.log(' [ok] git clone completed');
|
|
380
384
|
ponytailExtExists = await probeExt();
|
|
381
385
|
}
|
|
@@ -432,11 +436,11 @@ async function stepSelfPlugin(pluginsDir, options) {
|
|
|
432
436
|
await fs.mkdir(pluginsDir, { recursive: true });
|
|
433
437
|
await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
|
|
434
438
|
try {
|
|
435
|
-
await
|
|
439
|
+
await execNetwork('Installing Tersio plugin dependencies', 'npm', ['install', '--no-audit', '--no-fund'], { cwd: pluginsDir, timeout: 180000 });
|
|
436
440
|
}
|
|
437
441
|
catch {
|
|
438
442
|
try {
|
|
439
|
-
await
|
|
443
|
+
await execNetwork('Installing Tersio plugin dependencies', 'bun', ['install'], { cwd: pluginsDir, timeout: 180000 });
|
|
440
444
|
}
|
|
441
445
|
catch (e) {
|
|
442
446
|
console.log(` [fail] Could not install ${PACKAGE_NAME} into plugins dir: ${e.message}`);
|
|
@@ -535,7 +539,7 @@ async function extractRtkArchive(archivePath, extractDir) {
|
|
|
535
539
|
async function stepRtk(binDir, options) {
|
|
536
540
|
console.log('\n[3/7] Installing RTK binary...');
|
|
537
541
|
try {
|
|
538
|
-
const release = await fetchJson(RTK_RELEASE_API);
|
|
542
|
+
const release = await withInteractiveSpinner('Finding latest RTK release', () => fetchJson(RTK_RELEASE_API));
|
|
539
543
|
const triple = resolveRtkTriple();
|
|
540
544
|
if (!triple)
|
|
541
545
|
return;
|
|
@@ -552,10 +556,14 @@ async function stepRtk(binDir, options) {
|
|
|
552
556
|
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'omp-rtk-'));
|
|
553
557
|
try {
|
|
554
558
|
const archivePath = path.join(tmpDir, asset.name);
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
+
const checksumsText = await withInteractiveSpinner('Downloading RTK binary', async (update) => {
|
|
560
|
+
const [downloadedChecksums] = await Promise.all([
|
|
561
|
+
downloadRtkChecksums(release),
|
|
562
|
+
httpsDownload(asset.browser_download_url, archivePath),
|
|
563
|
+
]);
|
|
564
|
+
update('Verifying RTK checksum');
|
|
565
|
+
return downloadedChecksums;
|
|
566
|
+
});
|
|
559
567
|
if (!await verifyRtkArchive(archivePath, asset.name, checksumsText))
|
|
560
568
|
return;
|
|
561
569
|
const extractDir = path.join(tmpDir, 'extracted');
|
|
@@ -634,7 +642,7 @@ async function fetchCavemanRule(options) {
|
|
|
634
642
|
if (options.dryRun)
|
|
635
643
|
return (await readTextIfExists(path.join(path.dirname(CAVEMAN_INDEX), 'rule.md'))) || '';
|
|
636
644
|
try {
|
|
637
|
-
return await httpsGet(CAVEMAN_REMOTE_RULE);
|
|
645
|
+
return await withInteractiveSpinner('Fetching Caveman rule', () => httpsGet(CAVEMAN_REMOTE_RULE));
|
|
638
646
|
}
|
|
639
647
|
catch (e) {
|
|
640
648
|
console.log(` [warn] Could not fetch caveman rule: ${e.message}`);
|
|
@@ -690,29 +698,61 @@ async function runDoctor() {
|
|
|
690
698
|
const comboIndex = path.join(extDir, 'combo-toggle', 'index.js');
|
|
691
699
|
const modeReinforcement = path.join(extDir, 'shared', 'mode-reinforcement.js');
|
|
692
700
|
const selfPkg = path.join(pluginsDir, 'node_modules', PACKAGE_NAME, 'package.json');
|
|
693
|
-
// Independent probes
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
fs.readdir(
|
|
698
|
-
|
|
699
|
-
readTextIfExists(
|
|
700
|
-
readTextIfExists(
|
|
701
|
-
readTextIfExists(
|
|
702
|
-
readTextIfExists(
|
|
703
|
-
readTextIfExists(
|
|
704
|
-
readTextIfExists(
|
|
705
|
-
readTextIfExists(
|
|
706
|
-
readTextIfExists(
|
|
707
|
-
readTextIfExists(
|
|
708
|
-
readTextIfExists(
|
|
709
|
-
readTextIfExists(
|
|
710
|
-
readTextIfExists(
|
|
711
|
-
|
|
712
|
-
fs.stat(
|
|
713
|
-
fs.stat(
|
|
714
|
-
|
|
715
|
-
|
|
701
|
+
// Independent probes start concurrently; sections report in fixed order as
|
|
702
|
+
// their data settles. Every probe resolves instead of rejecting.
|
|
703
|
+
const probes = {
|
|
704
|
+
ompVersion: execP(OMP_BIN, ['--version']).then((r) => r.stdout.trim(), () => null),
|
|
705
|
+
agentEntries: fs.readdir(agentDir).catch(() => null),
|
|
706
|
+
extEntries: fs.readdir(extDir).catch(() => null),
|
|
707
|
+
sharedStateText: readTextIfExists(path.join(extDir, 'shared', 'session-state.js')),
|
|
708
|
+
configText: readTextIfExists(configPath),
|
|
709
|
+
ponytailPkgText: readTextIfExists(ponytailPkg),
|
|
710
|
+
ponytailExtText: readTextIfExists(ponytailExt),
|
|
711
|
+
pluginsPkgRaw: readTextIfExists(path.join(pluginsDir, 'package.json')),
|
|
712
|
+
selfPkgText: readTextIfExists(selfPkg),
|
|
713
|
+
rtkBinText: readTextIfExists(rtkBin),
|
|
714
|
+
cavemanIndexText: readTextIfExists(cavemanIndex),
|
|
715
|
+
cavemanRuleText: readTextIfExists(cavemanRule),
|
|
716
|
+
rtkIndexText: readTextIfExists(rtkIndex),
|
|
717
|
+
updaterIndexText: readTextIfExists(updaterIndex),
|
|
718
|
+
comboIndexText: readTextIfExists(comboIndex),
|
|
719
|
+
modeReinforcementText: readTextIfExists(modeReinforcement),
|
|
720
|
+
ruleMtime: fs.stat(cavemanRule).catch(() => null),
|
|
721
|
+
rtkMtime: fs.stat(rtkBin).catch(() => null),
|
|
722
|
+
ponytailMtime: fs.stat(ponytailPkg).catch(() => null),
|
|
723
|
+
updateVersion: checkForUpdate(),
|
|
724
|
+
};
|
|
725
|
+
const rtkVersionProbe = probes.rtkBinText.then((text) => text === null ? null : execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => r.stdout.trim() || r.stderr.trim() || null, (e) => {
|
|
726
|
+
const err = e;
|
|
727
|
+
return err.stdout?.trim() || err.stderr?.trim() || null;
|
|
728
|
+
}));
|
|
729
|
+
const [ompVersion, agentEntries, extEntries, sharedStateText, configText, updateVersion] = await runInteractivePhase('Checking environment and installation', () => Promise.all([
|
|
730
|
+
probes.ompVersion,
|
|
731
|
+
probes.agentEntries,
|
|
732
|
+
probes.extEntries,
|
|
733
|
+
probes.sharedStateText,
|
|
734
|
+
probes.configText,
|
|
735
|
+
probes.updateVersion,
|
|
736
|
+
]));
|
|
737
|
+
const [cavemanIndexText, rtkIndexText, updaterIndexText, comboIndexText, modeReinforcementText, ponytailPkgText, ponytailExtText, pluginsPkgRaw, selfPkgText] = await runInteractivePhase('Checking extensions and plugins', () => Promise.all([
|
|
738
|
+
probes.cavemanIndexText,
|
|
739
|
+
probes.rtkIndexText,
|
|
740
|
+
probes.updaterIndexText,
|
|
741
|
+
probes.comboIndexText,
|
|
742
|
+
probes.modeReinforcementText,
|
|
743
|
+
probes.ponytailPkgText,
|
|
744
|
+
probes.ponytailExtText,
|
|
745
|
+
probes.pluginsPkgRaw,
|
|
746
|
+
probes.selfPkgText,
|
|
747
|
+
]));
|
|
748
|
+
const [cavemanRuleText, ruleMtime, rtkBinText, rtkMtime, rtkVersion, ponytailMtime] = await runInteractivePhase('Checking add-ons', () => Promise.all([
|
|
749
|
+
probes.cavemanRuleText,
|
|
750
|
+
probes.ruleMtime,
|
|
751
|
+
probes.rtkBinText,
|
|
752
|
+
probes.rtkMtime,
|
|
753
|
+
rtkVersionProbe,
|
|
754
|
+
probes.ponytailMtime,
|
|
755
|
+
]));
|
|
716
756
|
// Categorized output with a tally; section headers group related probes.
|
|
717
757
|
const tally = { ok: 0, missing: 0, warn: 0 };
|
|
718
758
|
function check(label, ok, detail = '') {
|
|
@@ -761,10 +801,6 @@ async function runDoctor() {
|
|
|
761
801
|
section('Add-ons');
|
|
762
802
|
const ruleAge = ruleMtime ? `updated ${relTime(Date.now() - ruleMtime.mtimeMs)}` : '';
|
|
763
803
|
check('Caveman rule', cavemanRuleText !== null, ruleAge);
|
|
764
|
-
const rtkVersion = rtkBinText === null ? null : await execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => r.stdout.trim() || r.stderr.trim() || null, (e) => {
|
|
765
|
-
const err = e;
|
|
766
|
-
return err.stdout?.trim() || err.stderr?.trim() || null;
|
|
767
|
-
});
|
|
768
804
|
const rtkAge = rtkMtime ? `updated ${relTime(Date.now() - rtkMtime.mtimeMs)}` : '';
|
|
769
805
|
if (rtkBinText === null)
|
|
770
806
|
check('RTK binary', false, rtkBin);
|
|
@@ -866,11 +902,27 @@ async function runUninstall(options = {}) {
|
|
|
866
902
|
console.log(` ${rtkBin}`);
|
|
867
903
|
}
|
|
868
904
|
if (!confirmed) {
|
|
869
|
-
|
|
870
|
-
if (!answer.toLowerCase().startsWith('y')) {
|
|
871
|
-
console.log('Aborted.');
|
|
905
|
+
if (tty()) {
|
|
872
906
|
closeRL();
|
|
873
|
-
|
|
907
|
+
const confirmedChoice = await clackConfirm({ message: 'Remove the listed Tersio files?', initialValue: false });
|
|
908
|
+
if (typeof confirmedChoice !== 'boolean') {
|
|
909
|
+
clackCancel('Aborted.');
|
|
910
|
+
closeRL();
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
913
|
+
if (!confirmedChoice) {
|
|
914
|
+
console.log('Aborted.');
|
|
915
|
+
closeRL();
|
|
916
|
+
return false;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
const answer = await ask('\nProceed? [y/N]: ');
|
|
921
|
+
if (!answer.toLowerCase().startsWith('y')) {
|
|
922
|
+
console.log('Aborted.');
|
|
923
|
+
closeRL();
|
|
924
|
+
return false;
|
|
925
|
+
}
|
|
874
926
|
}
|
|
875
927
|
}
|
|
876
928
|
// Remove extension directories (independent paths, so concurrently).
|
|
@@ -929,7 +981,6 @@ async function runUninstall(options = {}) {
|
|
|
929
981
|
return true;
|
|
930
982
|
}
|
|
931
983
|
const SCOPE_MAP = { user: '1', project: '2', both: '3' };
|
|
932
|
-
const COMBO_MENU = { '1': 'off', '2': 'medium', '3': 'balanced', '4': 'max' };
|
|
933
984
|
// --- Update check (cached; used by the bare-invocation banner and doctor) ---
|
|
934
985
|
const UPDATE_CHECK_TTL_MS = 6 * 60 * 60 * 1000;
|
|
935
986
|
function newerThan(a, b) {
|
|
@@ -946,7 +997,7 @@ async function latestPublishedVersion() {
|
|
|
946
997
|
const args = IS_WINDOWS
|
|
947
998
|
? ['/d', '/s', '/c', 'npm', 'view', PACKAGE_NAME, 'version', '--prefer-online']
|
|
948
999
|
: ['view', PACKAGE_NAME, 'version', '--prefer-online'];
|
|
949
|
-
const r = await
|
|
1000
|
+
const r = await execNetwork('Checking npm registry for tersio updates', IS_WINDOWS ? process.env.ComSpec || 'cmd.exe' : 'npm', args, {
|
|
950
1001
|
timeout: 4000,
|
|
951
1002
|
maxBuffer: 1024 * 1024,
|
|
952
1003
|
windowsHide: true,
|
|
@@ -1024,7 +1075,7 @@ async function runLatestUpdate() {
|
|
|
1024
1075
|
else {
|
|
1025
1076
|
try {
|
|
1026
1077
|
const globalArgs = IS_WINDOWS ? ['/d', '/s', '/c', 'npm', 'install', '-g', `${PACKAGE_NAME}@latest`, '--no-audit', '--no-fund'] : ['install', '-g', `${PACKAGE_NAME}@latest`, '--no-audit', '--no-fund'];
|
|
1027
|
-
const globalResult = await
|
|
1078
|
+
const globalResult = await execNetwork('Updating global Tersio CLI', npmCommand, globalArgs, {
|
|
1028
1079
|
timeout: 300000,
|
|
1029
1080
|
maxBuffer: 10 * 1024 * 1024,
|
|
1030
1081
|
windowsHide: true,
|
|
@@ -1042,7 +1093,7 @@ async function runLatestUpdate() {
|
|
|
1042
1093
|
}
|
|
1043
1094
|
}
|
|
1044
1095
|
try {
|
|
1045
|
-
const result = await
|
|
1096
|
+
const result = await execNetwork('Running latest Tersio installer', npmCommand, npmCommandArgs, {
|
|
1046
1097
|
timeout: 300000,
|
|
1047
1098
|
maxBuffer: 10 * 1024 * 1024,
|
|
1048
1099
|
windowsHide: true,
|
|
@@ -1060,7 +1111,6 @@ async function runLatestUpdate() {
|
|
|
1060
1111
|
process.stdout.write(err.stdout);
|
|
1061
1112
|
if (err.stderr)
|
|
1062
1113
|
process.stderr.write(err.stderr);
|
|
1063
|
-
console.error(`\n[fail] Could not run ${PACKAGE_NAME}@latest: ${err.message}`);
|
|
1064
1114
|
process.exitCode = 1;
|
|
1065
1115
|
}
|
|
1066
1116
|
}
|
|
@@ -1076,6 +1126,47 @@ function defaultProfile() {
|
|
|
1076
1126
|
function tty() {
|
|
1077
1127
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
1078
1128
|
}
|
|
1129
|
+
let spinnerDepth = 0;
|
|
1130
|
+
// Run async work under a TTY-only timer spinner. The spinner is cleared before
|
|
1131
|
+
// the caller prints its normal result line, preserving locked output shapes.
|
|
1132
|
+
async function withInteractiveSpinner(message, work) {
|
|
1133
|
+
if (!tty() || spinnerDepth > 0)
|
|
1134
|
+
return work(() => { });
|
|
1135
|
+
// Clack manages stdin itself. Close the legacy question interface before its
|
|
1136
|
+
// first use; non-interactive callers never reach this branch.
|
|
1137
|
+
closeRL();
|
|
1138
|
+
const active = clackSpinner({ indicator: 'timer' });
|
|
1139
|
+
active.start(message);
|
|
1140
|
+
spinnerDepth += 1;
|
|
1141
|
+
try {
|
|
1142
|
+
return await work((next) => { active.message(next); });
|
|
1143
|
+
}
|
|
1144
|
+
finally {
|
|
1145
|
+
active.clear();
|
|
1146
|
+
spinnerDepth -= 1;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
async function askInteractiveChoice(message, options, initialValue) {
|
|
1150
|
+
if (!tty())
|
|
1151
|
+
return { status: 'unavailable' };
|
|
1152
|
+
closeRL();
|
|
1153
|
+
const choice = await clackSelect({ message, options, initialValue });
|
|
1154
|
+
if (typeof choice !== 'string') {
|
|
1155
|
+
clackCancel('Aborted.');
|
|
1156
|
+
return { status: 'cancelled' };
|
|
1157
|
+
}
|
|
1158
|
+
return { status: 'selected', value: choice };
|
|
1159
|
+
}
|
|
1160
|
+
// Run collecting work under one TTY-only Clack task. Callers print after the
|
|
1161
|
+
// task completes, keeping normal output out of the spinner animation.
|
|
1162
|
+
async function runInteractivePhase(title, collect) {
|
|
1163
|
+
if (!tty())
|
|
1164
|
+
return collect();
|
|
1165
|
+
closeRL();
|
|
1166
|
+
let result;
|
|
1167
|
+
await clackTasks([{ title, task: async () => { result = await collect(); } }]);
|
|
1168
|
+
return result;
|
|
1169
|
+
}
|
|
1079
1170
|
// Determine install scope: reinstall > flag > non-interactive default > prompt.
|
|
1080
1171
|
async function resolveScope() {
|
|
1081
1172
|
if (reinstall) {
|
|
@@ -1096,6 +1187,17 @@ async function resolveScope() {
|
|
|
1096
1187
|
console.log(` Scope: user (${install ? 'install default' : '--scope omitted, defaulting to user with --yes'})`);
|
|
1097
1188
|
return '1';
|
|
1098
1189
|
}
|
|
1190
|
+
if (tty()) {
|
|
1191
|
+
const choice = await askInteractiveChoice('Install scope', [
|
|
1192
|
+
{ value: '1', label: 'User-level', hint: 'all OMP sessions' },
|
|
1193
|
+
{ value: '2', label: 'Project-level', hint: 'this repo only' },
|
|
1194
|
+
{ value: '3', label: 'Both' },
|
|
1195
|
+
], '1');
|
|
1196
|
+
if (choice.status === 'selected')
|
|
1197
|
+
return choice.value;
|
|
1198
|
+
closeRL();
|
|
1199
|
+
process.exit(130);
|
|
1200
|
+
}
|
|
1099
1201
|
console.log('\nInstall scope:');
|
|
1100
1202
|
console.log(' 1) User-level (all OMP sessions)');
|
|
1101
1203
|
console.log(' 2) Project-level (this repo only)');
|
|
@@ -1114,22 +1216,17 @@ async function resolveProfile() {
|
|
|
1114
1216
|
// Only for a real user at a terminal, only when no default flags were
|
|
1115
1217
|
// given, and never for --apply-update runs.
|
|
1116
1218
|
if (tty() && !profileFlagsGiven && !applyUpdate && (install || reinstall)) {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
if (COMBO_MENU[answer]) {
|
|
1129
|
-
profile.comboDefault = COMBO_MENU[answer];
|
|
1130
|
-
break;
|
|
1131
|
-
}
|
|
1132
|
-
console.log(` [fail] Invalid choice: ${answer}. Choose 1, 2, 3, or 4.`);
|
|
1219
|
+
const choice = await askInteractiveChoice('Session-start defaults — Combo preset', [
|
|
1220
|
+
{ value: 'off', label: 'off' },
|
|
1221
|
+
{ value: 'medium', label: 'medium', hint: 'caveman=lite, rtk=on, ponytail=lite' },
|
|
1222
|
+
{ value: 'balanced', label: 'balanced', hint: 'caveman=full, rtk=on, ponytail=full' },
|
|
1223
|
+
{ value: 'max', label: 'max', hint: 'caveman=ultra, rtk=on, ponytail=ultra' },
|
|
1224
|
+
], 'off');
|
|
1225
|
+
if (choice.status === 'selected')
|
|
1226
|
+
profile.comboDefault = choice.value;
|
|
1227
|
+
else {
|
|
1228
|
+
closeRL();
|
|
1229
|
+
process.exit(130);
|
|
1133
1230
|
}
|
|
1134
1231
|
}
|
|
1135
1232
|
// Explicit flags always win over the Combo preset.
|