@krtclcdy/tersio 2.1.0 → 2.3.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 +7 -8
- package/package.json +1 -1
- package/tersio.js +105 -15
package/README.md
CHANGED
|
@@ -11,24 +11,23 @@ Terse replies, compact shell output, and minimal code decisions for [Oh My Pi (O
|
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
**Default** (macOS/Linux/WSL) — one line. Installs the CLI via npm, then runs the main installer (scope + Combo preset menus) in the same pass:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
17
|
+
curl -fsSL https://github.com/KurutoDenzeru/tersio/releases/latest/download/install.sh | sh
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Prefer OMP-managed updates and feature flags? Install as an OMP plugin instead:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
omp plugin install
|
|
24
|
-
omp plugin features @krtclcdy/tersio --disable rtk
|
|
23
|
+
omp plugin install @krtclcdy/tersio
|
|
25
24
|
```
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
Subset only:
|
|
28
27
|
|
|
29
28
|
```bash
|
|
30
|
-
|
|
31
|
-
tersio
|
|
29
|
+
omp plugin install '@krtclcdy/tersio[caveman,ponytail]'
|
|
30
|
+
omp plugin features @krtclcdy/tersio --disable rtk
|
|
32
31
|
```
|
|
33
32
|
|
|
34
33
|
Then restart OMP and enable a preset:
|
package/package.json
CHANGED
package/tersio.js
CHANGED
|
@@ -112,7 +112,18 @@ function debug(...a) {
|
|
|
112
112
|
const RL = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
113
113
|
let rlOpen = true;
|
|
114
114
|
function ask(q) {
|
|
115
|
-
return new Promise((resolve) =>
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
if (!rlOpen) {
|
|
117
|
+
resolve('');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
RL.question(q, resolve);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
resolve('');
|
|
125
|
+
}
|
|
126
|
+
});
|
|
116
127
|
}
|
|
117
128
|
function closeRL() { if (rlOpen) {
|
|
118
129
|
RL.close();
|
|
@@ -680,7 +691,7 @@ async function runDoctor() {
|
|
|
680
691
|
const modeReinforcement = path.join(extDir, 'shared', 'mode-reinforcement.js');
|
|
681
692
|
const selfPkg = path.join(pluginsDir, 'node_modules', PACKAGE_NAME, 'package.json');
|
|
682
693
|
// Independent probes run concurrently; logs below keep fixed order.
|
|
683
|
-
const [ompVersion, agentEntries, extEntries, sharedStateText, configText, ponytailPkgText, ponytailExtText, pluginsPkgRaw, selfPkgText, rtkBinText, cavemanIndexText, cavemanRuleText, rtkIndexText, updaterIndexText, comboIndexText, modeReinforcementText,] = await Promise.all([
|
|
694
|
+
const [ompVersion, agentEntries, extEntries, sharedStateText, configText, ponytailPkgText, ponytailExtText, pluginsPkgRaw, selfPkgText, rtkBinText, cavemanIndexText, cavemanRuleText, rtkIndexText, updaterIndexText, comboIndexText, modeReinforcementText, ruleMtime, rtkMtime, ponytailMtime, updateVersion,] = await Promise.all([
|
|
684
695
|
execP(OMP_BIN, ['--version']).then((r) => r.stdout.trim(), () => null),
|
|
685
696
|
fs.readdir(agentDir).catch(() => null),
|
|
686
697
|
fs.readdir(extDir).catch(() => null),
|
|
@@ -697,6 +708,10 @@ async function runDoctor() {
|
|
|
697
708
|
readTextIfExists(updaterIndex),
|
|
698
709
|
readTextIfExists(comboIndex),
|
|
699
710
|
readTextIfExists(modeReinforcement),
|
|
711
|
+
fs.stat(cavemanRule).catch(() => null),
|
|
712
|
+
fs.stat(rtkBin).catch(() => null),
|
|
713
|
+
fs.stat(ponytailPkg).catch(() => null),
|
|
714
|
+
checkForUpdate(),
|
|
700
715
|
]);
|
|
701
716
|
// Categorized output with a tally; section headers group related probes.
|
|
702
717
|
const tally = { ok: 0, missing: 0, warn: 0 };
|
|
@@ -717,6 +732,10 @@ async function runDoctor() {
|
|
|
717
732
|
section('Environment');
|
|
718
733
|
check('Node', true, process.version);
|
|
719
734
|
check('OMP CLI', ompVersion !== null, ompVersion ?? '');
|
|
735
|
+
if (updateVersion)
|
|
736
|
+
warnLine('Tersio CLI', `${updateVersion} available — run tersio update`);
|
|
737
|
+
else
|
|
738
|
+
check('Tersio CLI', true, PACKAGE_VERSION);
|
|
720
739
|
console.log(` Home: ${HOME}`);
|
|
721
740
|
section('Installation');
|
|
722
741
|
check('OMP agent dir', agentEntries !== null, agentDir);
|
|
@@ -725,7 +744,6 @@ async function runDoctor() {
|
|
|
725
744
|
check('Shared session bridge', sharedStateText !== null);
|
|
726
745
|
section('Extensions');
|
|
727
746
|
check('Caveman extension', cavemanIndexText !== null);
|
|
728
|
-
check('Caveman rule.md', cavemanRuleText !== null);
|
|
729
747
|
check('RTK extension', rtkIndexText !== null);
|
|
730
748
|
check('Updater extension', updaterIndexText !== null);
|
|
731
749
|
check('Combo extension', comboIndexText !== null);
|
|
@@ -737,22 +755,27 @@ async function runDoctor() {
|
|
|
737
755
|
check('Ponytail in config.yml', configText.includes('ponytail') && configText.includes('pi-extension'));
|
|
738
756
|
check('Combo in config.yml', configText.includes('combo-toggle'));
|
|
739
757
|
}
|
|
740
|
-
check('Self plugin package', selfPkgText !== null);
|
|
758
|
+
check('Self plugin package', selfPkgText !== null, parseJsonObject(selfPkgText)?.version ?? '');
|
|
741
759
|
const selfDep = PACKAGE_NAME in (parseJsonObject(pluginsPkgRaw)?.dependencies || {});
|
|
742
760
|
check('Self plugin in plugins/package.json', selfDep);
|
|
743
|
-
section('
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
761
|
+
section('Add-ons');
|
|
762
|
+
const ruleAge = ruleMtime ? `updated ${relTime(Date.now() - ruleMtime.mtimeMs)}` : '';
|
|
763
|
+
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
|
+
const rtkAge = rtkMtime ? `updated ${relTime(Date.now() - rtkMtime.mtimeMs)}` : '';
|
|
769
|
+
if (rtkBinText === null)
|
|
770
|
+
check('RTK binary', false, rtkBin);
|
|
771
|
+
else {
|
|
772
|
+
const bits = [rtkVersion, rtkAge].filter(Boolean).join(', ');
|
|
773
|
+
check('RTK binary', true, bits);
|
|
774
|
+
if (!rtkVersion)
|
|
754
775
|
warnLine('RTK version', 'unavailable — binary may not be executable');
|
|
755
776
|
}
|
|
777
|
+
const ponytailAge = ponytailMtime ? `updated ${relTime(Date.now() - ponytailMtime.mtimeMs)}` : '';
|
|
778
|
+
check('Ponytail', ponytailPkgText !== null, [parseJsonObject(ponytailPkgText)?.version ?? '', ponytailAge].filter(Boolean).join(', '));
|
|
756
779
|
const total = tally.ok + tally.missing + tally.warn;
|
|
757
780
|
console.log(`\n Summary: ${total} checks — ${tally.ok} ok, ${tally.warn} warn, ${tally.missing} missing`);
|
|
758
781
|
}
|
|
@@ -907,6 +930,66 @@ async function runUninstall(options = {}) {
|
|
|
907
930
|
}
|
|
908
931
|
const SCOPE_MAP = { user: '1', project: '2', both: '3' };
|
|
909
932
|
const COMBO_MENU = { '1': 'off', '2': 'medium', '3': 'balanced', '4': 'max' };
|
|
933
|
+
// --- Update check (cached; used by the bare-invocation banner and doctor) ---
|
|
934
|
+
const UPDATE_CHECK_TTL_MS = 6 * 60 * 60 * 1000;
|
|
935
|
+
function newerThan(a, b) {
|
|
936
|
+
const pa = a.replace(/^v/, '').split('.').map((n) => parseInt(n, 10) || 0);
|
|
937
|
+
const pb = b.replace(/^v/, '').split('.').map((n) => parseInt(n, 10) || 0);
|
|
938
|
+
for (let i = 0; i < 3; i++) {
|
|
939
|
+
if ((pa[i] || 0) !== (pb[i] || 0))
|
|
940
|
+
return (pa[i] || 0) > (pb[i] || 0);
|
|
941
|
+
}
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
async function latestPublishedVersion() {
|
|
945
|
+
try {
|
|
946
|
+
const args = IS_WINDOWS
|
|
947
|
+
? ['/d', '/s', '/c', 'npm', 'view', PACKAGE_NAME, 'version', '--prefer-online']
|
|
948
|
+
: ['view', PACKAGE_NAME, 'version', '--prefer-online'];
|
|
949
|
+
const r = await execP(IS_WINDOWS ? process.env.ComSpec || 'cmd.exe' : 'npm', args, {
|
|
950
|
+
timeout: 4000,
|
|
951
|
+
maxBuffer: 1024 * 1024,
|
|
952
|
+
windowsHide: true,
|
|
953
|
+
shell: false,
|
|
954
|
+
});
|
|
955
|
+
return r.stdout.trim() || null;
|
|
956
|
+
}
|
|
957
|
+
catch {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
// Returns a newer published version, or null. Reads the registry at most once
|
|
962
|
+
// per TTL (cached under OMP_PLUGINS_DIR) and stays silent on failure.
|
|
963
|
+
async function checkForUpdate() {
|
|
964
|
+
const cachePath = path.join(OMP_PLUGINS_DIR, 'tersio-update-check.json');
|
|
965
|
+
const cached = parseJsonObject(await readTextIfExists(cachePath));
|
|
966
|
+
const cacheFresh = typeof cached?.lastCheck === 'number' && Date.now() - cached.lastCheck < UPDATE_CHECK_TTL_MS;
|
|
967
|
+
if (cacheFresh && cached?.latest)
|
|
968
|
+
return newerThan(cached.latest, PACKAGE_VERSION) ? cached.latest : null;
|
|
969
|
+
const latest = await latestPublishedVersion();
|
|
970
|
+
if (latest) {
|
|
971
|
+
await fs.mkdir(OMP_PLUGINS_DIR, { recursive: true }).catch(() => { });
|
|
972
|
+
await fs.writeFile(cachePath, JSON.stringify({ latest, lastCheck: Date.now() }) + '\n', 'utf8').catch(() => { });
|
|
973
|
+
return newerThan(latest, PACKAGE_VERSION) ? latest : null;
|
|
974
|
+
}
|
|
975
|
+
// Registry unreachable: fall back to a stale cache rather than staying silent.
|
|
976
|
+
return cached?.latest && newerThan(cached.latest, PACKAGE_VERSION) ? cached.latest : null;
|
|
977
|
+
}
|
|
978
|
+
function relTime(ageMs) {
|
|
979
|
+
const mins = Math.floor(ageMs / 60000);
|
|
980
|
+
if (mins < 1)
|
|
981
|
+
return 'just now';
|
|
982
|
+
if (mins < 60)
|
|
983
|
+
return `${mins} min${mins === 1 ? '' : 's'} ago`;
|
|
984
|
+
const hours = Math.floor(mins / 60);
|
|
985
|
+
if (hours < 24)
|
|
986
|
+
return `${hours} hour${hours === 1 ? '' : 's'} ago`;
|
|
987
|
+
const days = Math.floor(hours / 24);
|
|
988
|
+
if (days < 14)
|
|
989
|
+
return `${days} day${days === 1 ? '' : 's'} ago`;
|
|
990
|
+
const weeks = Math.floor(days / 7);
|
|
991
|
+
return `${weeks} week${weeks === 1 ? '' : 's'} ago`;
|
|
992
|
+
}
|
|
910
993
|
async function runLatestUpdate() {
|
|
911
994
|
const updateScope = scopeFlag || 'user';
|
|
912
995
|
if (!Object.hasOwn(SCOPE_MAP, updateScope)) {
|
|
@@ -1163,6 +1246,13 @@ async function main() {
|
|
|
1163
1246
|
console.log(` Platform: ${process.platform}`);
|
|
1164
1247
|
console.log(` Arch: ${process.arch}`);
|
|
1165
1248
|
console.log(` Home: ${HOME}`);
|
|
1249
|
+
// Remind humans a newer release exists; silent for scripts (no TTY) and for
|
|
1250
|
+
// the apply-update payload, which is itself an update run.
|
|
1251
|
+
if (tty() && !applyUpdate && command !== 'uninstall') {
|
|
1252
|
+
const newer = await checkForUpdate();
|
|
1253
|
+
if (newer)
|
|
1254
|
+
console.log(`\n [update] tersio ${newer} available (installed ${PACKAGE_VERSION}) — run \`tersio update\``);
|
|
1255
|
+
}
|
|
1166
1256
|
const scope = await resolveScope();
|
|
1167
1257
|
// Resolve session defaults: flags > interactive prompt > defaults.
|
|
1168
1258
|
const profile = await resolveProfile();
|