@krtclcdy/tersio 2.22.1 → 2.23.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 +25 -22
- package/cli/common.js +40 -36
- package/cli/dashboard.js +27 -12
- package/cli/doctor-fix.js +35 -29
- package/cli/doctor.js +26 -15
- package/cli/install.js +13 -32
- package/cli/profile.js +1 -0
- package/cli/settings.js +1 -1
- package/cli/update.js +12 -11
- package/cli/usage.js +6 -1
- package/dashboard/dist/index.html +1 -1
- package/extensions/ai-addons-updater/index.js +7 -3
- package/extensions/ai-addons-updater/index.ts +15 -3
- package/extensions/caveman-session/index.js +17 -12
- package/extensions/caveman-session/index.ts +17 -12
- package/extensions/caveman-session/rule.md +90 -0
- package/extensions/combo-toggle/index.js +22 -2
- package/extensions/combo-toggle/index.ts +26 -2
- package/extensions/lib/utils.js +20 -4
- package/extensions/lib/utils.ts +18 -4
- package/extensions/rtk-session/index.js +11 -10
- package/extensions/rtk-session/index.ts +10 -11
- package/extensions/shared/plugin-settings.js +37 -3
- package/extensions/shared/plugin-settings.ts +34 -3
- package/extensions/shared/rtk-gain.js +2 -2
- package/extensions/shared/rtk-gain.ts +3 -3
- package/extensions/shared/session-state.js +5 -3
- package/extensions/shared/session-state.ts +4 -3
- package/extensions/shared/types.ts +5 -0
- package/extensions/shared/usage-ledger.js +113 -3
- package/extensions/shared/usage-ledger.ts +121 -3
- package/package.json +12 -6
- package/tersio.js +2 -2
- package/extensions/shared/mode-reinforcement.ts +0 -29
package/cli/install.js
CHANGED
|
@@ -3,14 +3,13 @@ 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, 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,
|
|
6
|
+
import { BUN_BIN_DIR, COMBO_PRESET_MODES, 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, ensurePonytailConfigValue, execP, parseJsonObject, readPluginsPackage, writeIfChanged, } from './common.js';
|
|
7
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';
|
|
11
11
|
import { runDoctor } from './doctor.js';
|
|
12
12
|
import { runReset } from './reset.js';
|
|
13
|
-
import { runSettings } from './settings.js';
|
|
14
13
|
import { runUsage } from './usage.js';
|
|
15
14
|
import { runDashboard } from './dashboard.js';
|
|
16
15
|
import { wireRtkOmp } from './rtk-wiring.js';
|
|
@@ -20,18 +19,18 @@ import { storedProfile, writePluginSettings } from './profile.js';
|
|
|
20
19
|
const EXT_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'extensions');
|
|
21
20
|
const SHARED_SESSION_STATE = path.join(EXT_DIR, 'shared', 'session-state.ts');
|
|
22
21
|
const CAVEMAN_INDEX = path.join(EXT_DIR, 'caveman-session', 'index.ts');
|
|
22
|
+
const CAVEMAN_RULE = path.join(EXT_DIR, 'caveman-session', 'rule.md');
|
|
23
23
|
const RTK_SESSION_INDEX = path.join(EXT_DIR, 'rtk-session', 'index.ts');
|
|
24
24
|
const UPDATER_INDEX = path.join(EXT_DIR, 'ai-addons-updater', 'index.ts');
|
|
25
25
|
const COMBO_TOGGLE_INDEX = path.join(EXT_DIR, 'combo-toggle', 'index.ts');
|
|
26
26
|
const TERSIO_COMMANDS_INDEX = path.join(EXT_DIR, 'tersio-commands', 'index.ts');
|
|
27
|
-
const MODE_REINFORCEMENT_INDEX = path.join(EXT_DIR, 'shared', 'mode-reinforcement.ts');
|
|
28
27
|
const SHARED_TYPES = path.join(EXT_DIR, 'shared', 'types.ts');
|
|
29
28
|
const LIB_UTILS = path.join(EXT_DIR, 'lib', 'utils.ts');
|
|
30
29
|
const SHARED_PLUGIN_SETTINGS = path.join(EXT_DIR, 'shared', 'plugin-settings.ts');
|
|
31
30
|
const SHARED_USAGE_LEDGER = path.join(EXT_DIR, 'shared', 'usage-ledger.ts');
|
|
32
31
|
const SHARED_PRICING = path.join(EXT_DIR, 'shared', 'pricing.ts');
|
|
33
32
|
const SHARED_CARBON = path.join(EXT_DIR, 'shared', 'carbon.ts');
|
|
34
|
-
async function stepPonytail(pluginsDir,
|
|
33
|
+
async function stepPonytail(pluginsDir, options) {
|
|
35
34
|
if (!options.quiet)
|
|
36
35
|
console.log(' Ponytail — ensure bundled plugin');
|
|
37
36
|
await fs.mkdir(pluginsDir, { recursive: true });
|
|
@@ -92,12 +91,8 @@ async function stepPonytail(pluginsDir, userDir, options) {
|
|
|
92
91
|
console.log(' [hint] The /ponytail command won\'t work, but ponytail skills will still load');
|
|
93
92
|
}
|
|
94
93
|
else if (!options.dryRun && !options.quiet) {
|
|
95
|
-
|
|
96
|
-
debug('Bundled Ponytail pi-extension found');
|
|
94
|
+
debug('Bundled Ponytail pi-extension found; OMP loads it from the plugin manifest');
|
|
97
95
|
}
|
|
98
|
-
// Still set Ponytail config defaults even without the extension command
|
|
99
|
-
const configPath = path.join(userDir, 'config.yml');
|
|
100
|
-
await ensureExtensionInConfig(configPath, ponytailExtPath, 'ponytail', options);
|
|
101
96
|
await ensurePonytailConfigValue('defaultMode', 'off', options);
|
|
102
97
|
// hideStatus=true keeps the upstream ponytail bar hidden; combo owns the bar.
|
|
103
98
|
await ensurePonytailConfigValue('hideStatus', true, options);
|
|
@@ -355,14 +350,6 @@ async function stepSharedSessionState(extDir, options) {
|
|
|
355
350
|
[SHARED_CARBON, path.join('shared', 'carbon.ts')],
|
|
356
351
|
], 'shared/session-state.js', options);
|
|
357
352
|
}
|
|
358
|
-
async function stepModeReinforcement(extDir, ponytailExtPath, options) {
|
|
359
|
-
if (!options.quiet)
|
|
360
|
-
console.log(' Session helpers — sync shared files');
|
|
361
|
-
const dest = path.join(extDir, 'shared', 'mode-reinforcement.ts');
|
|
362
|
-
if (!await copySources(extDir, [[MODE_REINFORCEMENT_INDEX, path.join('shared', 'mode-reinforcement.ts')]], 'shared/mode-reinforcement.ts', options))
|
|
363
|
-
return;
|
|
364
|
-
await ensureExtensionAfterConfigEntry(path.join(path.dirname(extDir), 'config.yml'), dest, ponytailExtPath, 'mode reinforcement', options);
|
|
365
|
-
}
|
|
366
353
|
async function stepRtkSession(extDir, options) {
|
|
367
354
|
if (!options.quiet)
|
|
368
355
|
console.log(' RTK session — install session mode');
|
|
@@ -371,12 +358,17 @@ async function stepRtkSession(extDir, options) {
|
|
|
371
358
|
// One rule fetch serves the install; dry runs stay offline
|
|
372
359
|
// and fall back to the bundled rule to preview its destination.
|
|
373
360
|
async function fetchCavemanRule(options) {
|
|
361
|
+
const bundled = await readTextIfExists(CAVEMAN_RULE);
|
|
374
362
|
if (options.dryRun)
|
|
375
|
-
return
|
|
363
|
+
return bundled;
|
|
376
364
|
try {
|
|
377
365
|
return await withInteractiveSpinner('Fetching Caveman rule', () => httpsGet(CAVEMAN_REMOTE_RULE));
|
|
378
366
|
}
|
|
379
367
|
catch (e) {
|
|
368
|
+
if (bundled !== null) {
|
|
369
|
+
debug(`Using bundled Caveman rule: ${e.message}`);
|
|
370
|
+
return bundled;
|
|
371
|
+
}
|
|
380
372
|
console.log(` [warn] Could not fetch caveman rule: ${e.message}`);
|
|
381
373
|
return null;
|
|
382
374
|
}
|
|
@@ -411,12 +403,7 @@ async function stepUpdater(extDir, options) {
|
|
|
411
403
|
async function stepCombo(extDir, options) {
|
|
412
404
|
if (!options.quiet)
|
|
413
405
|
console.log(' Combo — install preset switch');
|
|
414
|
-
|
|
415
|
-
if (!await copySources(extDir, [[COMBO_TOGGLE_INDEX, path.join('combo-toggle', 'index.ts')]], 'combo-toggle/index.ts', options))
|
|
416
|
-
return;
|
|
417
|
-
// Auto-register combo in config.yml
|
|
418
|
-
const configPath = path.join(path.dirname(extDir), 'config.yml');
|
|
419
|
-
await ensureExtensionInConfig(configPath, dest, 'combo', options);
|
|
406
|
+
await copySources(extDir, [[COMBO_TOGGLE_INDEX, path.join('combo-toggle', 'index.ts')]], 'combo-toggle/index.ts', options);
|
|
420
407
|
}
|
|
421
408
|
async function resolveProfile(forceReinstall = false, opts = {}) {
|
|
422
409
|
// Seed from the lock file so flag-less update/reinstall runs keep the
|
|
@@ -486,7 +473,6 @@ async function runCommandMenu() {
|
|
|
486
473
|
{ value: 'usage', label: 'Usage', hint: 'token usage and savings report' },
|
|
487
474
|
{ value: 'dashboard', label: 'Dashboard', hint: 'open the report in your browser' },
|
|
488
475
|
{ value: 'reset', label: 'Reset statistics', hint: 'clear statistics; transcripts and RTK history stay' },
|
|
489
|
-
{ value: 'settings', label: 'Settings', hint: 'defaults: combo, caveman, rtk, ponytail, currency' },
|
|
490
476
|
{ value: 'uninstall', label: 'Uninstall', hint: 'remove tersio' },
|
|
491
477
|
], 'install');
|
|
492
478
|
if (choice.status !== 'selected') {
|
|
@@ -553,9 +539,6 @@ async function runCommandMenu() {
|
|
|
553
539
|
await runReset();
|
|
554
540
|
closeRL();
|
|
555
541
|
break;
|
|
556
|
-
case 'settings':
|
|
557
|
-
await runSettings();
|
|
558
|
-
break;
|
|
559
542
|
case 'uninstall':
|
|
560
543
|
await runUninstall();
|
|
561
544
|
closeRL();
|
|
@@ -644,14 +627,12 @@ async function runInstall(overrides = {}) {
|
|
|
644
627
|
await capture('shared', () => stepSharedSessionState(userExtDir, options));
|
|
645
628
|
let selfPlugin = false;
|
|
646
629
|
await capture('self-plugin', async () => { selfPlugin = await stepSelfPlugin(OMP_PLUGINS_DIR, options); });
|
|
647
|
-
await capture('ponytail', () => stepPonytail(OMP_PLUGINS_DIR,
|
|
648
|
-
const ponytailExtPath = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'pi-extension', 'index.js');
|
|
630
|
+
await capture('ponytail', () => stepPonytail(OMP_PLUGINS_DIR, options));
|
|
649
631
|
await capture('rtk', () => stepRtk(BUN_BIN_DIR, options));
|
|
650
632
|
await capture('rtk session', () => stepRtkSession(userExtDir, options));
|
|
651
|
-
await capture('caveman', () => stepCaveman(
|
|
633
|
+
await capture('caveman', () => stepCaveman(path.join(OMP_PLUGINS_DIR, 'node_modules', '@krtclcdy', 'tersio', 'extensions'), cavemanRule, options));
|
|
652
634
|
await capture('combo', () => stepCombo(userExtDir, options));
|
|
653
635
|
await capture('commands', () => stepTersioCommands(userExtDir, options));
|
|
654
|
-
await capture('reinforcement', () => stepModeReinforcement(userExtDir, ponytailExtPath, options));
|
|
655
636
|
await capture('updater', () => stepUpdater(userExtDir, options));
|
|
656
637
|
if (selfPlugin)
|
|
657
638
|
await capture('settings', () => writePluginSettings(profile, options));
|
package/cli/profile.js
CHANGED
|
@@ -72,6 +72,7 @@ async function writePluginSettings(profile, options) {
|
|
|
72
72
|
config.settings[PACKAGE_NAME] = {
|
|
73
73
|
...(config.settings[PACKAGE_NAME] || {}),
|
|
74
74
|
comboDefault: profile.comboDefault,
|
|
75
|
+
comboSetupComplete: true,
|
|
75
76
|
cavemanDefault: profile.cavemanDefault,
|
|
76
77
|
rtkDefault: profile.rtkDefault,
|
|
77
78
|
ponytailDefault: profile.ponytailDefault,
|
package/cli/settings.js
CHANGED
|
@@ -85,7 +85,7 @@ async function askDiagSchedule(current) {
|
|
|
85
85
|
}
|
|
86
86
|
const SETTING_NAMES = ['combo', 'caveman', 'rtk', 'ponytail', 'currency', 'diagnosis'];
|
|
87
87
|
function settingsUsage() {
|
|
88
|
-
console.log(' Usage: tersio settings [combo|caveman|rtk|ponytail|currency|diagnosis] [--combo-default off|medium|balanced|max] [--caveman-default off|lite|full|ultra|wenyan] [--rtk-default on|off] [--ponytail-default off|lite|full|ultra
|
|
88
|
+
console.log(' Usage: tersio settings [combo|caveman|rtk|ponytail|currency|diagnosis] [--combo-default off|medium|balanced|max] [--caveman-default off|lite|full|ultra|wenyan-lite|wenyan-full|wenyan-ultra] [--rtk-default on|off] [--ponytail-default off|lite|full|ultra] [--currency USD|PHP|EUR|GBP|JPY|KRW|SGD|AUD|CAD|INR] [--diag-schedule manual|daily|weekly|monthly] [--dry-run]');
|
|
89
89
|
}
|
|
90
90
|
// Single-setting jump: `tersio settings diagnosis` prompts only that value
|
|
91
91
|
// instead of walking the whole chain. Returns false when aborted.
|
package/cli/update.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
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 {
|
|
5
|
+
import { IS_WINDOWS, OMP_PLUGINS_DIR, PACKAGE_BIN, PACKAGE_NAME, PACKAGE_VERSION, dryRun, execP, parseJsonObject, verbose, } from './common.js';
|
|
6
6
|
import { execNetwork } from './interactive.js';
|
|
7
|
-
import { readTextIfExists, tersioDataPath } from '../extensions/lib/utils.js';
|
|
7
|
+
import { readTextIfExists, resolveRtkBinary, tersioDataPath } from '../extensions/lib/utils.js';
|
|
8
8
|
import { refreshPrices } from '../extensions/shared/pricing.js';
|
|
9
|
-
import { CAVEMAN_REMOTE_RULE, RTK_RELEASE_API,
|
|
9
|
+
import { CAVEMAN_REMOTE_RULE, RTK_RELEASE_API, httpsGet, normalizeRtkVersion, sha256Hex, } from '../extensions/lib/utils.js';
|
|
10
10
|
const UPDATE_CHECK_TTL_MS = 6 * 60 * 60 * 1000;
|
|
11
11
|
function newerThan(a, b) {
|
|
12
12
|
const pa = a.replace(/^v/, '').split('.').map((n) => parseInt(n, 10) || 0);
|
|
@@ -83,21 +83,22 @@ async function execInherit(cmd, args) {
|
|
|
83
83
|
// Current → latest per add-on. Every probe is capped and nullable; the plan
|
|
84
84
|
// prints `unknown` for anything unreachable and the update proceeds anyway.
|
|
85
85
|
async function probeUpdatePlan(cliLatest) {
|
|
86
|
-
const rtkBin =
|
|
86
|
+
const rtkBin = resolveRtkBinary();
|
|
87
87
|
const ponytailPkg = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'package.json');
|
|
88
|
-
const
|
|
88
|
+
const tersioRule = path.join(OMP_PLUGINS_DIR, 'node_modules', '@krtclcdy', 'tersio', 'extensions', 'caveman-session', 'rule.md');
|
|
89
|
+
const controller = new AbortController();
|
|
89
90
|
const [rtkLocal, rtkRelease, ruleLocalText, ruleRemoteText, ponytailLocalText] = await Promise.all([
|
|
90
|
-
settle(execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => normalizeRtkVersion(r.stdout.trim() || r.stderr.trim()) || null), 6000),
|
|
91
|
-
settle(
|
|
92
|
-
readTextIfExists(
|
|
93
|
-
settle(httpsGet(CAVEMAN_REMOTE_RULE),
|
|
91
|
+
settle(rtkBin ? execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => normalizeRtkVersion(r.stdout.trim() || r.stderr.trim()) || null) : Promise.resolve(null), 6000),
|
|
92
|
+
settle(httpsGet(RTK_RELEASE_API, { signal: controller.signal }).then((text) => normalizeRtkVersion(JSON.parse(text).tag_name) || null), 1500),
|
|
93
|
+
readTextIfExists(tersioRule),
|
|
94
|
+
settle(httpsGet(CAVEMAN_REMOTE_RULE, { signal: controller.signal }).then((text) => sha256Hex(text).slice(0, 8)), 1500),
|
|
94
95
|
readTextIfExists(ponytailPkg),
|
|
95
96
|
]);
|
|
96
|
-
|
|
97
|
+
controller.abort();
|
|
97
98
|
return {
|
|
98
99
|
cli: cliLatest,
|
|
99
100
|
rtk: [rtkLocal, rtkRelease],
|
|
100
|
-
rule: [
|
|
101
|
+
rule: [ruleLocalText ? sha256Hex(ruleLocalText).slice(0, 8) : null, ruleRemoteText],
|
|
101
102
|
ponytail: ponytailLocalText ? parseJsonObject(ponytailLocalText)?.version ?? null : null,
|
|
102
103
|
};
|
|
103
104
|
}
|
package/cli/usage.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
// cli/usage.ts — ledger + session-token usage report, tokscale-style.
|
|
2
|
+
import { co2GramsFor, displayModelId, energyWhFor, importSessionTokens, ledgerPath, priceFor, readResetWatermark, readRtkAdoption, readRtkRecallDiagnostics, readUsage, refreshPricesIfStale, sessionsDir, usdCost, } from '../extensions/shared/usage-ledger.js';
|
|
3
|
+
import { resolveRtkBinary } from '../extensions/lib/utils.js';
|
|
2
4
|
import { readRtkGain } from '../extensions/shared/rtk-gain.js';
|
|
3
5
|
import { readUsageDb, syncUsageDb, usageDbPath } from '../extensions/shared/usage-store.js';
|
|
4
6
|
import { withInteractiveSpinner } from './interactive.js';
|
|
@@ -74,6 +76,8 @@ export function summarizeUsage(rows) {
|
|
|
74
76
|
est: usdCost({ input: r.i, output: r.o, cacheRead: r.cr ?? 0, cacheWrite: r.cw ?? 0 }, r.m).usd,
|
|
75
77
|
})),
|
|
76
78
|
rtkGain: readRtkGain(RTK_COMMAND_ROWS, watermark || undefined),
|
|
79
|
+
rtkAdoption: readRtkAdoption(),
|
|
80
|
+
rtkRecall: readRtkRecallDiagnostics(resolveRtkBinary()),
|
|
77
81
|
usd,
|
|
78
82
|
priced,
|
|
79
83
|
savedUsd,
|
|
@@ -134,6 +138,7 @@ function printReport(report) {
|
|
|
134
138
|
const t = report.tokens;
|
|
135
139
|
console.log(` TOKENS ${fmt(t.input)} in · ${fmt(t.output)} out · ${fmt(t.cacheRead)} cache read · ${fmt(t.cacheWrite)} cache write`);
|
|
136
140
|
console.log(` COST ${formatCurrency(report.usd, report.currency)}${report.priced ? '' : ' (includes default pricing)'} · ~${formatCurrency(report.savedUsd, report.currency)} cache-saved (est.) · ~${report.co2g.toFixed(1)}g CO2 (est.)`);
|
|
141
|
+
console.log(` RTK ${fmt(report.rtkAdoption.rtkCalls)}/${fmt(report.rtkAdoption.eligibleCalls)} eligible OMP Bash calls use RTK (${report.rtkAdoption.adoptionPct.toFixed(1)}%) · ${fmt(report.rtkAdoption.missedCalls)} missed · recall ${report.rtkRecall.available ? `${report.rtkRecall.mode} (${report.rtkRecall.entries})` : 'unavailable'}`);
|
|
137
142
|
const models = Object.entries(report.byModel).filter(([, b]) => b.input + b.output + b.cacheRead + b.cacheWrite > 0).sort((a, b) => (b[1].input + b[1].output) - (a[1].input + a[1].output)).slice(0, 8);
|
|
138
143
|
if (models.length) {
|
|
139
144
|
console.log(' BY MODEL');
|