@krtclcdy/tersio 2.11.0 → 2.12.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 CHANGED
@@ -97,7 +97,7 @@ Break-even math, balanced preset (caveman full + rtk + ponytail): `⌈overhead
97
97
 
98
98
  | Command | Purpose |
99
99
  |---|---|
100
- | `tersio install` | Install (user scope by default; `--scope project\|both` for more) |
100
+ | `tersio install` | Install (user scope: all OMP sessions) |
101
101
  | `tersio update` | Refresh the CLI, extensions, and add-ons (RTK binary, Caveman rule, Ponytail) |
102
102
  | `tersio reinstall` | Fresh install, preserving the Ponytail package |
103
103
  | `tersio doctor` | Check OMP, extension, Ponytail, and RTK health |
@@ -107,7 +107,7 @@ Break-even math, balanced preset (caveman full + rtk + ponytail): `⌈overhead
107
107
  | `tersio uninstall` | Remove extensions, registration, and the Ponytail plugin (`--keep-ponytail` keeps Ponytail; `--remove-rtk` also removes the RTK binary) |
108
108
  | `tersio version` | Print version |
109
109
 
110
- Flags: `--dry-run`, `--yes`/`-y`, `--verbose`, `--scope`, `--combo-default`/`--caveman-default`/`--rtk-default`/`--ponytail-default`. Legacy `--doctor` / `--uninstall` forms still work.
110
+ Flags: `--dry-run`, `--yes`/`-y`, `--verbose`, `--combo-default`/`--caveman-default`/`--rtk-default`/`--ponytail-default`. Legacy `--doctor` / `--uninstall` forms still work.
111
111
 
112
112
  ## ⌨️ Commands reference
113
113
 
package/cli/common.js CHANGED
@@ -48,7 +48,7 @@ function flagValue(name) {
48
48
  // --- CLI flags ---
49
49
  const COMMANDS = { install: true, update: true, reinstall: true, doctor: true, uninstall: true, usage: true, gain: true, reset: true, version: true, help: true };
50
50
  const args = process.argv.slice(2);
51
- const commandArg = args.find((arg, index) => !arg.startsWith('-') && args[index - 1] !== '--scope');
51
+ const commandArg = args.find((arg) => !arg.startsWith('-'));
52
52
  const command = commandArg?.toLowerCase() || null;
53
53
  const unknownCommand = command !== null && !COMMANDS[command];
54
54
  const install = command === 'install';
@@ -71,7 +71,13 @@ const uninstall = command === 'uninstall' || args.includes('--uninstall');
71
71
  const removePonytail = args.includes('--remove-ponytail');
72
72
  const keepPonytail = args.includes('--keep-ponytail');
73
73
  const removeRtk = args.includes('--remove-rtk');
74
- const scopeFlag = flagValue('--scope')?.toLowerCase() ?? null;
74
+ // Project scope was removed: tersio installs user-level (all OMP sessions)
75
+ // only. A bare `--scope user` still parses (old scripts); anything else fails.
76
+ const legacyScope = flagValue('--scope')?.toLowerCase() ?? null;
77
+ if (legacyScope !== null && legacyScope !== 'user') {
78
+ console.error(`[fail] Invalid --scope: ${legacyScope}. Project scope was removed; tersio installs user-level only.`);
79
+ process.exit(1);
80
+ }
75
81
  // --- Profile selection (session-start mode defaults) ---
76
82
  const comboDefaultFlag = parseEnum(flagValue('--combo-default'), COMBO_DEFAULTS, '--combo-default');
77
83
  const cavemanDefaultFlag = parseEnum(flagValue('--caveman-default'), CAVEMAN_DEFAULTS, '--caveman-default');
@@ -239,7 +245,6 @@ async function readPluginsPackage(pkgPath) {
239
245
  const pkg = parseJsonObject(await readTextIfExists(pkgPath)) ?? {};
240
246
  return { ...pkg, name: pkg.name || 'omp-plugins', private: true, dependencies: pkg.dependencies || {} };
241
247
  }
242
- const SCOPE_MAP = { user: '1', project: '2', both: '3' };
243
248
  function relTime(ageMs) {
244
249
  const mins = Math.floor(ageMs / 60000);
245
250
  if (mins < 1)
@@ -255,4 +260,4 @@ function relTime(ageMs) {
255
260
  const weeks = Math.floor(days / 7);
256
261
  return `${weeks} week${weeks === 1 ? '' : 's'} ago`;
257
262
  }
258
- export { IS_WINDOWS, RTK_BINARY_NAME, HOME, OMP_AGENT_DIR, OMP_PLUGINS_DIR, BUN_BIN_DIR, OMP_BIN, PACKAGE_NAME, PACKAGE_BIN, PACKAGE_VERSION, CAVEMAN_DEFAULTS, PONYTAIL_DEFAULTS, RTK_DEFAULTS, COMBO_PRESET_MODES, COMBO_DEFAULTS, parseEnum, flagValue, COMMANDS, commandArg, command, unknownCommand, install, update, reinstall, showVersion, showHelp, applyUpdate, dryRun, yes, verbose, doctor, uninstall, usage, gain, reset, dashboardPort, dashboardOpen, dashboardExport, removePonytail, keepPonytail, removeRtk, scopeFlag, comboDefaultFlag, cavemanDefaultFlag, ponytailDefaultFlag, rtkDefaultFlag, profileFlagsGiven, debug, execFileP, execP, writeIfChanged, normalizeExtensionsKey, EXTENSIONS_KEY_RE, writeConfigLines, ensureExtensionInConfig, ensureExtensionAfterConfigEntry, readPonytailConfig, parseJsonObject, parsePonytailConfig, patchPonytailConfig, ensurePonytailConfigValue, readPluginsPackage, SCOPE_MAP, relTime, };
263
+ export { IS_WINDOWS, RTK_BINARY_NAME, HOME, OMP_AGENT_DIR, OMP_PLUGINS_DIR, BUN_BIN_DIR, OMP_BIN, PACKAGE_NAME, PACKAGE_BIN, PACKAGE_VERSION, CAVEMAN_DEFAULTS, PONYTAIL_DEFAULTS, RTK_DEFAULTS, COMBO_PRESET_MODES, COMBO_DEFAULTS, parseEnum, flagValue, COMMANDS, commandArg, command, unknownCommand, install, update, reinstall, showVersion, showHelp, applyUpdate, dryRun, yes, verbose, doctor, uninstall, usage, gain, reset, dashboardPort, dashboardOpen, dashboardExport, removePonytail, keepPonytail, removeRtk, comboDefaultFlag, cavemanDefaultFlag, ponytailDefaultFlag, rtkDefaultFlag, profileFlagsGiven, debug, execFileP, execP, writeIfChanged, normalizeExtensionsKey, EXTENSIONS_KEY_RE, writeConfigLines, ensureExtensionInConfig, ensureExtensionAfterConfigEntry, readPonytailConfig, parseJsonObject, parsePonytailConfig, patchPonytailConfig, ensurePonytailConfigValue, readPluginsPackage, relTime, };
package/cli/install.js CHANGED
@@ -3,8 +3,8 @@ import { promises as fs } from 'node:fs';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
- import { BUN_BIN_DIR, COMBO_PRESET_MODES, EXTENSIONS_KEY_RE, HOME, IS_WINDOWS, OMP_AGENT_DIR, OMP_PLUGINS_DIR, OMP_BIN, PACKAGE_NAME, PACKAGE_VERSION, RTK_BINARY_NAME, SCOPE_MAP, applyUpdate, cavemanDefaultFlag, comboDefaultFlag, command, dryRun, install, ponytailDefaultFlag, profileFlagsGiven, reinstall, rtkDefaultFlag, scopeFlag, verbose, yes, dashboardExport, dashboardPort, debug, ensureExtensionAfterConfigEntry, ensureExtensionInConfig, ensurePonytailConfigValue, execP, parseJsonObject, readPluginsPackage, writeIfChanged, } from './common.js';
7
- import { ask, askInteractiveChoice, askInteractiveConfirm, closeRL, execNetwork, tty, withInteractiveSpinner, } from './interactive.js';
6
+ import { BUN_BIN_DIR, COMBO_PRESET_MODES, EXTENSIONS_KEY_RE, HOME, IS_WINDOWS, OMP_AGENT_DIR, OMP_PLUGINS_DIR, OMP_BIN, PACKAGE_NAME, PACKAGE_VERSION, RTK_BINARY_NAME, applyUpdate, cavemanDefaultFlag, comboDefaultFlag, command, dryRun, install, ponytailDefaultFlag, profileFlagsGiven, reinstall, rtkDefaultFlag, verbose, yes, dashboardExport, dashboardPort, debug, ensureExtensionAfterConfigEntry, ensureExtensionInConfig, ensurePonytailConfigValue, execP, parseJsonObject, readPluginsPackage, writeIfChanged, } from './common.js';
7
+ import { askInteractiveChoice, askInteractiveConfirm, closeRL, execNetwork, tty, withInteractiveSpinner, } from './interactive.js';
8
8
  import { printWelcome } from './banner.js';
9
9
  import { checkForUpdate, runLatestUpdate } from './update.js';
10
10
  import { runUninstall } from './uninstall.js';
@@ -25,6 +25,9 @@ const MODE_REINFORCEMENT_INDEX = path.join(EXT_DIR, 'shared', 'mode-reinforcemen
25
25
  const SHARED_TYPES = path.join(EXT_DIR, 'shared', 'types.js');
26
26
  const LIB_UTILS = path.join(EXT_DIR, 'lib', 'utils.js');
27
27
  const SHARED_PLUGIN_SETTINGS = path.join(EXT_DIR, 'shared', 'plugin-settings.js');
28
+ const SHARED_USAGE_LEDGER = path.join(EXT_DIR, 'shared', 'usage-ledger.js');
29
+ const SHARED_PRICING = path.join(EXT_DIR, 'shared', 'pricing.js');
30
+ const SHARED_CARBON = path.join(EXT_DIR, 'shared', 'carbon.js');
28
31
  const PONYTAIL_GITHUB_SPEC = 'github:DietrichGebert/ponytail';
29
32
  const PONYTAIL_NPM_SPEC = '@dietrichgebert/ponytail@latest';
30
33
  async function stepPonytail(pluginsDir, userDir, options) {
@@ -345,6 +348,9 @@ async function stepSharedSessionState(extDir, options) {
345
348
  [SHARED_TYPES, path.join('shared', 'types.js')],
346
349
  [LIB_UTILS, path.join('lib', 'utils.js')],
347
350
  [SHARED_PLUGIN_SETTINGS, path.join('shared', 'plugin-settings.js')],
351
+ [SHARED_USAGE_LEDGER, path.join('shared', 'usage-ledger.js')],
352
+ [SHARED_PRICING, path.join('shared', 'pricing.js')],
353
+ [SHARED_CARBON, path.join('shared', 'carbon.js')],
348
354
  ], 'shared/session-state.js', options);
349
355
  }
350
356
  async function stepModeReinforcement(extDir, ponytailExtPath, options) {
@@ -358,7 +364,7 @@ async function stepRtkSession(extDir, options) {
358
364
  console.log('\n[4/8] Installing RTK session extension...');
359
365
  await copySources(extDir, [[RTK_SESSION_INDEX, path.join('rtk-session', 'index.js')]], 'rtk-session/index.js', options);
360
366
  }
361
- // One rule fetch serves user- and project-level installs; dry runs stay offline
367
+ // One rule fetch serves the install; dry runs stay offline
362
368
  // and fall back to the bundled rule to preview its destination.
363
369
  async function fetchCavemanRule(options) {
364
370
  if (options.dryRun)
@@ -413,52 +419,12 @@ function defaultProfile() {
413
419
  ponytailDefault: 'off',
414
420
  };
415
421
  }
416
- // Determine install scope: reinstall > flag > non-interactive default > prompt.
417
- async function resolveScope() {
418
- if (reinstall) {
419
- console.log(' Scope: user (reinstall)');
420
- return '1';
421
- }
422
- if (scopeFlag) {
423
- const scope = SCOPE_MAP[scopeFlag];
424
- if (!scope) {
425
- console.log(` [fail] Invalid --scope: ${scopeFlag}. Use: user, project, both`);
426
- closeRL();
427
- process.exit(1);
428
- }
429
- console.log(` Scope: ${scopeFlag}`);
430
- return scope;
431
- }
432
- if (install || yes) {
433
- console.log(` Scope: user (${install ? 'install default' : '--scope omitted, defaulting to user with --yes'})`);
434
- return '1';
435
- }
436
- if (tty()) {
437
- const choice = await askInteractiveChoice('Install scope', [
438
- { value: '1', label: 'User-level', hint: 'all OMP sessions' },
439
- { value: '2', label: 'Project-level', hint: 'this repo only' },
440
- { value: '3', label: 'Both' },
441
- ], '1');
442
- if (choice.status === 'selected')
443
- return choice.value;
444
- closeRL();
445
- process.exit(130);
446
- }
447
- console.log('\nInstall scope:');
448
- console.log(' 1) User-level (all OMP sessions)');
449
- console.log(' 2) Project-level (this repo only)');
450
- console.log(' 3) Both');
451
- while (true) {
452
- const answer = (await ask('\nChoose [1-3] (default 1): ')).trim() || '1';
453
- if (answer === '1' || answer === '2' || answer === '3')
454
- return answer;
455
- console.log(` [fail] Invalid scope: ${answer}. Choose 1, 2, or 3.`);
456
- }
457
- }
422
+ // Install is always user-level (all OMP sessions). Project scope was removed:
423
+ // session extensions must live in ~/.omp/agent/extensions to load.
458
424
  async function resolveProfile() {
459
425
  const profile = defaultProfile();
460
426
  // Single interactive prompt: the Combo preset implies all three modes.
461
- // Numbered menu, same pattern as the scope prompt — no typing preset names.
427
+ // Numbered menu — no typing preset names.
462
428
  // Only for a real user at a terminal, only when no default flags were
463
429
  // given, and never for --apply-update runs.
464
430
  if (tty() && !profileFlagsGiven && !applyUpdate && (install || reinstall)) {
@@ -568,7 +534,7 @@ async function runCommandMenu() {
568
534
  }
569
535
  updatePromptDone = true;
570
536
  const choice = await askInteractiveChoice('Tersio — what next?', [
571
- { value: 'install', label: 'Install add-ons', hint: 'user/project scope + combo defaults' },
537
+ { value: 'install', label: 'Install add-ons', hint: 'user scope + combo defaults' },
572
538
  { value: 'check', label: 'Check for updates', hint: 'check CLI version, then update ai-addons' },
573
539
  { value: 'doctor', label: 'Doctor', hint: 'verify the installation' },
574
540
  { value: 'usage', label: 'Usage', hint: 'token usage and savings report' },
@@ -674,16 +640,15 @@ async function runInstall() {
674
640
  }
675
641
  }
676
642
  }
677
- const scope = await resolveScope();
643
+ console.log(' Scope: user (all OMP sessions)');
678
644
  // Resolve session defaults: flags > interactive prompt > defaults.
679
645
  const profile = await resolveProfile();
680
646
  const userDir = OMP_AGENT_DIR;
681
647
  const userExtDir = path.join(userDir, 'extensions');
682
- const projectExtDir = path.join(process.cwd(), '.omp', 'extensions');
683
648
  // apply-update is `tersio update`'s payload run: treat it like reinstall so
684
649
  // the add-ons refresh too — Ponytail package via npm, self plugin, RTK
685
650
  // binary (always re-downloaded), and the Caveman rule (always re-fetched).
686
- const options = { dryRun, verbose, yes, scope, reinstall: reinstall || applyUpdate };
651
+ const options = { dryRun, verbose, yes, reinstall: reinstall || applyUpdate };
687
652
  // Check prerequisites
688
653
  console.log('\nPrerequisites:');
689
654
  try {
@@ -694,32 +659,20 @@ async function runInstall() {
694
659
  console.log(' [fail] omp not found — ensure it\'s installed');
695
660
  }
696
661
  const cavemanRule = await fetchCavemanRule(options);
697
- if (scope === '1' || scope === '3') {
698
- console.log('\n--- User-level install ---');
699
- await stepSharedSessionState(userExtDir, options);
700
- await stepPonytail(OMP_PLUGINS_DIR, userDir, options);
701
- const selfPlugin = await stepSelfPlugin(OMP_PLUGINS_DIR, options);
702
- const ponytailExtPath = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'pi-extension', 'index.js');
703
- await stepRtk(BUN_BIN_DIR, options);
704
- await stepRtkSession(userExtDir, options);
705
- await stepCaveman(userExtDir, cavemanRule, options);
706
- await stepCombo(userExtDir, options);
707
- await stepTersioCommands(userExtDir, options);
708
- await stepModeReinforcement(userExtDir, ponytailExtPath, options);
709
- await stepUpdater(userExtDir, options);
710
- if (selfPlugin)
711
- await writePluginSettings(profile, options);
712
- await validateConfigExtensions(userDir, options);
713
- }
714
- if (scope === '2' || scope === '3') {
715
- console.log('\n--- Project-level install ---');
716
- await stepSharedSessionState(projectExtDir, options);
717
- await stepRtkSession(projectExtDir, options);
718
- await stepCaveman(projectExtDir, cavemanRule, options);
719
- await stepTersioCommands(projectExtDir, options);
720
- await stepUpdater(projectExtDir, options);
721
- console.log(' [note] Ponytail, RTK binary, and Combo toggle require user-level (global) install');
722
- }
662
+ console.log('\n--- User-level install ---');
663
+ await stepSharedSessionState(userExtDir, options);
664
+ await stepPonytail(OMP_PLUGINS_DIR, userDir, options);
665
+ const selfPlugin = await stepSelfPlugin(OMP_PLUGINS_DIR, options);
666
+ const ponytailExtPath = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'pi-extension', 'index.js');
667
+ await stepRtk(BUN_BIN_DIR, options);
668
+ await stepRtkSession(userExtDir, options);
669
+ await stepCaveman(userExtDir, cavemanRule, options);
670
+ await stepCombo(userExtDir, options);
671
+ await stepTersioCommands(userExtDir, options);
672
+ await stepModeReinforcement(userExtDir, ponytailExtPath, options);
673
+ await stepUpdater(userExtDir, options);
674
+ if (selfPlugin)
675
+ await writePluginSettings(profile, options);
723
676
  console.log('\n=== Installation complete ===');
724
677
  console.log('\nNext steps:');
725
678
  console.log(' 1. Restart OMP');
package/cli/uninstall.js CHANGED
@@ -168,5 +168,4 @@ async function runUninstall(options = {}) {
168
168
  console.log('\nDone. Restart OMP for changes to take effect.');
169
169
  return true;
170
170
  }
171
- const SCOPE_MAP = { user: '1', project: '2', both: '3' };
172
171
  export { runUninstall };
package/cli/update.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { promises as fs } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { spawn } from 'node:child_process';
5
- import { BUN_BIN_DIR, IS_WINDOWS, OMP_AGENT_DIR, OMP_PLUGINS_DIR, PACKAGE_BIN, PACKAGE_NAME, PACKAGE_VERSION, RTK_BINARY_NAME, SCOPE_MAP, dryRun, execP, parseJsonObject, scopeFlag, verbose, } from './common.js';
5
+ import { BUN_BIN_DIR, IS_WINDOWS, OMP_AGENT_DIR, OMP_PLUGINS_DIR, PACKAGE_BIN, PACKAGE_NAME, PACKAGE_VERSION, RTK_BINARY_NAME, dryRun, execP, parseJsonObject, verbose, } from './common.js';
6
6
  import { execNetwork } from './interactive.js';
7
7
  import { readTextIfExists } from '../extensions/lib/utils.js';
8
8
  import { refreshPrices } from '../extensions/shared/pricing.js';
@@ -127,13 +127,7 @@ function planLine(name, current, latest) {
127
127
  console.log(` ${name}: ${current ?? 'missing'} → ${latest}`);
128
128
  }
129
129
  async function runLatestUpdate() {
130
- const updateScope = scopeFlag || 'user';
131
- if (!Object.hasOwn(SCOPE_MAP, updateScope)) {
132
- console.error(`[fail] Invalid --scope: ${updateScope}. Use: user, project, both`);
133
- process.exitCode = 1;
134
- return;
135
- }
136
- const forwardedArgs = ['--yes', '--scope', updateScope];
130
+ const forwardedArgs = ['--yes'];
137
131
  if (dryRun)
138
132
  forwardedArgs.push('--dry-run');
139
133
  if (verbose)
@@ -172,6 +172,7 @@
172
172
  }
173
173
  /* Empty states (shadcn pattern): dashed well, icon chip, title + hint. */
174
174
  .empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 2px; border: 1px dashed var(--line); border-radius: 12px; padding: 32px 16px; }
175
+ .empty.hidden { display: none; } /* beats .empty flex: same-file order, higher specificity than tailwind .hidden */
175
176
  .empty-icon { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 999px; background: var(--track); color: var(--dim); margin-bottom: 10px; }
176
177
  .empty-title { font-weight: 600; font-size: 14px; color: var(--ink); margin: 0; }
177
178
  .empty-desc { font-size: 12px; color: var(--dim); margin: 0; max-width: 340px; }
@@ -188,7 +189,7 @@
188
189
  .dlg-hint { font-size: 12px; color: var(--dim); margin: 2px 0 0; }
189
190
  .dlg-own { font-weight: 400; font-size: 11px; color: var(--dim); }
190
191
  .dlg-paths { margin-top: 12px; display: grid; gap: 8px; }
191
- .dlg-path { border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px; }
192
+ .dlg-path { border: 1px solid var(--line); border-radius: 10px; padding: 8px 12px; min-width: 0; overflow: hidden; }
192
193
  .dlg-file { font-size: 11px; color: var(--dim); margin: 4px 0 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
193
194
  #settingsBtn:hover { box-shadow: 0 0 14px var(--accent-soft); border-color: var(--accent); }
194
195
  .dlg .seg button { display: grid; place-items: center; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krtclcdy/tersio",
3
- "version": "2.11.0",
3
+ "version": "2.12.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
@@ -15,7 +15,7 @@ function printHelp() {
15
15
  console.log(`Usage: ${PACKAGE_BIN} [command] [options]
16
16
 
17
17
  Commands:
18
- install Install the add-ons (user scope by default)
18
+ install Install the add-ons (user scope: all OMP sessions)
19
19
  update Refresh the CLI and add-ons (RTK binary, Caveman rule, Ponytail)
20
20
  reinstall Clean and reinstall the user-scope add-ons
21
21
  doctor Check the current installation
@@ -27,7 +27,7 @@ Commands:
27
27
  help Show this help
28
28
 
29
29
  Options:
30
- --scope user|project|both
30
+ --scope user (legacy; accepted and ignored — user scope is the only scope)
31
31
  --keep-ponytail (uninstall: keep the Ponytail plugin — removed by default)
32
32
  --remove-rtk (uninstall: also remove the RTK binary)
33
33
  --combo-default off|medium|balanced|max (implies caveman, rtk, ponytail)