@krtclcdy/tersio 2.0.1 → 2.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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/tersio.js +105 -52
package/README.md CHANGED
@@ -79,7 +79,7 @@ Break-even math, balanced preset (caveman full + rtk + ponytail): `⌈overhead
79
79
  | Command | Purpose |
80
80
  |---|---|
81
81
  | `tersio install` | Install (user scope by default; `--scope project\|both` for more) |
82
- | `tersio update` | Refresh from the latest release |
82
+ | `tersio update` | Refresh the CLI, extensions, and add-ons (RTK binary, Caveman rule, Ponytail) |
83
83
  | `tersio reinstall` | Fresh install, preserving the Ponytail package |
84
84
  | `tersio doctor` | Check OMP, extension, Ponytail, and RTK health |
85
85
  | `tersio uninstall` | Remove extensions, registration, and the Ponytail plugin (`--keep-ponytail` keeps Ponytail; `--remove-rtk` also removes the RTK binary) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krtclcdy/tersio",
3
- "version": "2.0.1",
3
+ "version": "2.1.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",
package/tersio.js CHANGED
@@ -84,7 +84,7 @@ function printHelp() {
84
84
 
85
85
  Commands:
86
86
  install Install the add-ons (user scope by default)
87
- update Run the latest published installer
87
+ update Refresh the CLI and add-ons (RTK binary, Caveman rule, Ponytail)
88
88
  reinstall Clean and reinstall the user-scope add-ons
89
89
  doctor Check the current installation
90
90
  uninstall Remove the managed extensions
@@ -661,17 +661,8 @@ async function stepCombo(extDir, options) {
661
661
  await ensureExtensionInConfig(configPath, dest, 'combo', options);
662
662
  }
663
663
  // --- Doctor ---
664
- function presence(label, text) {
665
- console.log(` ${label}: ${text !== null ? 'installed' : 'MISSING'}`);
666
- }
667
- function locationLine(label, ok, loc) {
668
- console.log(` ${label}: ${ok ? 'ok' : 'MISSING'} ${loc}`);
669
- }
670
664
  async function runDoctor() {
671
- console.log('\n=== Tersio Doctor ===\n');
672
- // Node
673
- console.log(` Node: ok ${process.version}`);
674
- // OMP CLI version joins FS probes below; logs keep fixed order.
665
+ console.log('\n=== Tersio Doctor ===');
675
666
  // Directories
676
667
  const agentDir = OMP_AGENT_DIR;
677
668
  const extDir = path.join(agentDir, 'extensions');
@@ -707,48 +698,66 @@ async function runDoctor() {
707
698
  readTextIfExists(comboIndex),
708
699
  readTextIfExists(modeReinforcement),
709
700
  ]);
710
- console.log(ompVersion !== null ? ` OMP CLI: ok ${ompVersion}` : ' OMP CLI: MISSING');
711
- console.log(` Home: ${HOME}`);
712
- locationLine('OMP agent dir', agentEntries !== null, agentDir);
713
- locationLine('OMP extensions dir', extEntries !== null, extDir);
714
- console.log(` Shared session bridge: ${sharedStateText !== null ? 'installed' : 'MISSING'}`);
715
- locationLine('OMP config.yml', configText !== null, configPath);
716
- presence('Ponytail package', ponytailPkgText);
717
- presence('Ponytail extension', ponytailExtText);
718
- if (configText) {
719
- const hasPonytailPath = configText.includes('ponytail') && configText.includes('pi-extension');
720
- console.log(` Ponytail in config.yml: ${hasPonytailPath ? 'registered' : 'MISSING'}`);
721
- }
722
- // Self plugin registration (Settings → Plugins listing)
723
- const selfDep = PACKAGE_NAME in (parseJsonObject(pluginsPkgRaw)?.dependencies || {});
724
- console.log(` Self plugin in plugins/package.json: ${selfDep ? 'registered' : 'MISSING'}`);
725
- console.log(` Self plugin package: ${selfPkgText !== null ? 'installed' : 'MISSING'}`);
726
- // RTK
727
- const rtkExists = rtkBinText !== null;
728
- console.log(` RTK binary: ${rtkExists ? 'installed' : 'MISSING'} ${rtkBin}`);
729
- if (rtkExists) {
730
- try {
731
- const v = (await execP(rtkBin, ['--version'], { timeout: 5000 })).stdout.trim();
732
- console.log(` RTK version: ${v}`);
701
+ // Categorized output with a tally; section headers group related probes.
702
+ const tally = { ok: 0, missing: 0, warn: 0 };
703
+ function check(label, ok, detail = '') {
704
+ if (ok) {
705
+ tally.ok++;
706
+ console.log(` ${label}: ok${detail ? ` ${detail}` : ''}`);
733
707
  }
734
- catch {
735
- console.log(' RTK version: unavailable (may not be executable)');
708
+ else {
709
+ tally.missing++;
710
+ console.log(` ${label}: MISSING${detail ? ` ${detail}` : ''}`);
736
711
  }
737
712
  }
738
- // Caveman
739
- presence('Caveman extension', cavemanIndexText);
740
- presence('Caveman rule.md', cavemanRuleText);
741
- // RTK extension
742
- presence('RTK extension', rtkIndexText);
743
- // Updater
744
- presence('Updater extension', updaterIndexText);
745
- // Combo
746
- presence('Combo extension', comboIndexText);
747
- presence('Mode reinforcement extension', modeReinforcementText);
713
+ function warnLine(label, detail) {
714
+ tally.warn++;
715
+ console.log(` ${label}: warn ${detail}`);
716
+ }
717
+ section('Environment');
718
+ check('Node', true, process.version);
719
+ check('OMP CLI', ompVersion !== null, ompVersion ?? '');
720
+ console.log(` Home: ${HOME}`);
721
+ section('Installation');
722
+ check('OMP agent dir', agentEntries !== null, agentDir);
723
+ check('OMP extensions dir', extEntries !== null, extDir);
724
+ check('OMP config.yml', configText !== null, configPath);
725
+ check('Shared session bridge', sharedStateText !== null);
726
+ section('Extensions');
727
+ check('Caveman extension', cavemanIndexText !== null);
728
+ check('Caveman rule.md', cavemanRuleText !== null);
729
+ check('RTK extension', rtkIndexText !== null);
730
+ check('Updater extension', updaterIndexText !== null);
731
+ check('Combo extension', comboIndexText !== null);
732
+ check('Mode reinforcement extension', modeReinforcementText !== null);
733
+ section('Plugins');
734
+ check('Ponytail package', ponytailPkgText !== null);
735
+ check('Ponytail extension', ponytailExtText !== null);
748
736
  if (configText) {
749
- const hasComboPath = configText.includes('combo-toggle');
750
- console.log(` Combo in config.yml: ${hasComboPath ? 'registered' : 'MISSING'}`);
737
+ check('Ponytail in config.yml', configText.includes('ponytail') && configText.includes('pi-extension'));
738
+ check('Combo in config.yml', configText.includes('combo-toggle'));
751
739
  }
740
+ check('Self plugin package', selfPkgText !== null);
741
+ const selfDep = PACKAGE_NAME in (parseJsonObject(pluginsPkgRaw)?.dependencies || {});
742
+ check('Self plugin in plugins/package.json', selfDep);
743
+ section('RTK');
744
+ check('RTK binary', rtkBinText !== null, rtkBin);
745
+ if (rtkBinText !== null) {
746
+ // rtk may exit non-zero while still printing its version — accept either stream.
747
+ const version = await execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => r.stdout.trim() || r.stderr.trim() || null, (e) => {
748
+ const err = e;
749
+ return err.stdout?.trim() || err.stderr?.trim() || null;
750
+ });
751
+ if (version)
752
+ check('RTK version', true, version);
753
+ else
754
+ warnLine('RTK version', 'unavailable — binary may not be executable');
755
+ }
756
+ const total = tally.ok + tally.missing + tally.warn;
757
+ console.log(`\n Summary: ${total} checks — ${tally.ok} ok, ${tally.warn} warn, ${tally.missing} missing`);
758
+ }
759
+ function section(name) {
760
+ console.log(`\n${name}`);
752
761
  }
753
762
  // Read-modify-write a JSON file. mutate returns true when it changed
754
763
  // something; no change (or unreadable file) means no output at all.
@@ -897,6 +906,7 @@ async function runUninstall(options = {}) {
897
906
  return true;
898
907
  }
899
908
  const SCOPE_MAP = { user: '1', project: '2', both: '3' };
909
+ const COMBO_MENU = { '1': 'off', '2': 'medium', '3': 'balanced', '4': 'max' };
900
910
  async function runLatestUpdate() {
901
911
  const updateScope = scopeFlag || 'user';
902
912
  if (!Object.hasOwn(SCOPE_MAP, updateScope)) {
@@ -923,6 +933,31 @@ async function runLatestUpdate() {
923
933
  const npmCommandArgs = IS_WINDOWS ? ['/d', '/s', '/c', 'npm', ...npmArgs] : npmArgs;
924
934
  console.log('=== Updating Tersio ===');
925
935
  console.log(` Running the latest ${PACKAGE_NAME} installer...\n`);
936
+ // The npx delegation below only refreshes the OMP-side files; the globally
937
+ // installed CLI keeps its old version until npm -g runs. Refresh both.
938
+ if (dryRun) {
939
+ console.log(` [dry-run] would run: npm install -g ${PACKAGE_NAME}@latest --no-audit --no-fund`);
940
+ }
941
+ else {
942
+ try {
943
+ 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'];
944
+ const globalResult = await execP(npmCommand, globalArgs, {
945
+ timeout: 300000,
946
+ maxBuffer: 10 * 1024 * 1024,
947
+ windowsHide: true,
948
+ shell: false,
949
+ });
950
+ if (globalResult.stdout)
951
+ process.stdout.write(globalResult.stdout);
952
+ if (globalResult.stderr)
953
+ process.stderr.write(globalResult.stderr);
954
+ console.log(` [ok] CLI updated to ${PACKAGE_NAME}@latest`);
955
+ }
956
+ catch (e) {
957
+ console.log(` [warn] Global CLI update skipped: ${e.message}`);
958
+ console.log(` [hint] Manual: npm install -g ${PACKAGE_NAME}@latest`);
959
+ }
960
+ }
926
961
  try {
927
962
  const result = await execP(npmCommand, npmCommandArgs, {
928
963
  timeout: 300000,
@@ -992,12 +1027,27 @@ async function resolveScope() {
992
1027
  async function resolveProfile() {
993
1028
  const profile = defaultProfile();
994
1029
  // Single interactive prompt: the Combo preset implies all three modes.
1030
+ // Numbered menu, same pattern as the scope prompt — no typing preset names.
995
1031
  // Only for a real user at a terminal, only when no default flags were
996
1032
  // given, and never for --apply-update runs.
997
1033
  if (tty() && !profileFlagsGiven && !applyUpdate && (install || reinstall)) {
998
- const comboAnswer = (await ask(' Default Combo preset on session start? [off/medium/balanced/max] (off): ')).trim().toLowerCase();
999
- if (comboAnswer && COMBO_DEFAULTS.has(comboAnswer))
1000
- profile.comboDefault = comboAnswer;
1034
+ console.log(' Session-start defaults — Combo preset:');
1035
+ console.log(' 1) off');
1036
+ console.log(' 2) medium (caveman=lite, rtk=on, ponytail=lite)');
1037
+ console.log(' 3) balanced (caveman=full, rtk=on, ponytail=full)');
1038
+ console.log(' 4) max (caveman=ultra, rtk=on, ponytail=ultra)');
1039
+ for (;;) {
1040
+ const answer = (await ask(' Choose [1-4] (default 1): ')).trim();
1041
+ if (!answer) {
1042
+ profile.comboDefault = 'off';
1043
+ break;
1044
+ }
1045
+ if (COMBO_MENU[answer]) {
1046
+ profile.comboDefault = COMBO_MENU[answer];
1047
+ break;
1048
+ }
1049
+ console.log(` [fail] Invalid choice: ${answer}. Choose 1, 2, 3, or 4.`);
1050
+ }
1001
1051
  }
1002
1052
  // Explicit flags always win over the Combo preset.
1003
1053
  if (comboDefaultFlag !== undefined)
@@ -1119,7 +1169,10 @@ async function main() {
1119
1169
  const userDir = OMP_AGENT_DIR;
1120
1170
  const userExtDir = path.join(userDir, 'extensions');
1121
1171
  const projectExtDir = path.join(process.cwd(), '.omp', 'extensions');
1122
- const options = { dryRun, verbose, yes, scope, reinstall };
1172
+ // apply-update is `tersio update`'s payload run: treat it like reinstall so
1173
+ // the add-ons refresh too — Ponytail package via npm, self plugin, RTK
1174
+ // binary (always re-downloaded), and the Caveman rule (always re-fetched).
1175
+ const options = { dryRun, verbose, yes, scope, reinstall: reinstall || applyUpdate };
1123
1176
  // Check prerequisites
1124
1177
  console.log('\nPrerequisites:');
1125
1178
  try {