@krtclcdy/tersio 2.22.1 → 2.24.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 +62 -46
- package/cli/agent-hosts.js +42 -0
- package/cli/agents.js +266 -0
- package/cli/common.js +55 -55
- package/cli/currency.js +8 -12
- package/cli/dashboard.js +76 -49
- package/cli/doctor-fix.js +61 -44
- package/cli/doctor.js +66 -44
- package/cli/hosts.js +118 -0
- package/cli/install.js +187 -143
- package/cli/interactive.js +27 -1
- package/cli/layer.js +24 -0
- package/cli/manifest.js +36 -0
- package/cli/omp-layer.js +51 -0
- package/cli/pi-layer.js +37 -0
- package/cli/pi-wiring.js +92 -0
- package/cli/profile.js +45 -46
- package/cli/reset.js +3 -26
- package/cli/rtk-wiring.js +10 -15
- package/cli/settings.js +1 -1
- package/cli/uninstall.js +135 -44
- package/cli/update.js +24 -30
- package/cli/usage.js +6 -1
- package/dashboard/dist/index.html +16 -16
- package/extensions/ai-addons-updater/index.js +36 -25
- package/extensions/ai-addons-updater/index.ts +36 -24
- package/extensions/caveman-session/index.js +23 -18
- package/extensions/caveman-session/index.ts +23 -18
- package/extensions/caveman-session/rule.md +90 -0
- package/extensions/combo-toggle/index.js +63 -41
- package/extensions/combo-toggle/index.ts +61 -48
- package/extensions/lib/utils.js +56 -13
- package/extensions/lib/utils.ts +55 -13
- package/extensions/rtk-session/index.js +20 -19
- package/extensions/rtk-session/index.ts +18 -24
- package/extensions/shared/carbon.js +5 -8
- package/extensions/shared/carbon.ts +5 -8
- package/extensions/shared/host.js +68 -0
- package/extensions/shared/host.ts +104 -0
- package/extensions/shared/omp-prompt.js +12 -0
- package/extensions/shared/plugin-settings.js +63 -16
- package/extensions/shared/plugin-settings.ts +67 -17
- package/extensions/shared/pricing.js +26 -15
- package/extensions/shared/pricing.ts +28 -16
- package/extensions/shared/rtk-gain.js +13 -24
- package/extensions/shared/rtk-gain.ts +14 -25
- package/extensions/shared/session-state.js +26 -28
- package/extensions/shared/session-state.ts +26 -29
- package/extensions/shared/types.ts +15 -3
- package/extensions/shared/usage-ledger.js +136 -38
- package/extensions/shared/usage-ledger.ts +149 -52
- package/extensions/shared/usage-store.js +14 -12
- package/extensions/shared/usage-store.ts +16 -14
- package/extensions/tersio-commands/index.js +2 -1
- package/extensions/tersio-commands/index.ts +2 -1
- package/package.json +15 -7
- package/tersio.js +6 -6
- package/extensions/shared/mode-reinforcement.js +0 -26
- package/extensions/shared/mode-reinforcement.ts +0 -29
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);
|
|
@@ -34,10 +34,8 @@ async function latestPublishedVersion() {
|
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
// (cached under OMP_PLUGINS_DIR) unless force skips the cache — an explicit
|
|
40
|
-
// "check for updates" must never trust a stale cache.
|
|
37
|
+
// A newer published version, null when up to date, 'unknown' when the registry
|
|
38
|
+
// is unreachable. Cached for a TTL unless force, which must not trust a cache.
|
|
41
39
|
async function checkForUpdate(force = false) {
|
|
42
40
|
const cachePath = tersioDataPath('update-check.json', 'tersio-update-check.json');
|
|
43
41
|
const cached = parseJsonObject(await readTextIfExists(cachePath));
|
|
@@ -50,12 +48,11 @@ async function checkForUpdate(force = false) {
|
|
|
50
48
|
await fs.writeFile(cachePath, JSON.stringify({ latest, lastCheck: Date.now() }) + '\n', 'utf8').catch(() => { });
|
|
51
49
|
return newerThan(latest, PACKAGE_VERSION) ? latest : null;
|
|
52
50
|
}
|
|
53
|
-
//
|
|
54
|
-
// actionable
|
|
51
|
+
// Unreachable registry: a stale cache naming a newer release is still
|
|
52
|
+
// actionable, else report unknown so nobody claims "latest".
|
|
55
53
|
return cached?.latest && newerThan(cached.latest, PACKAGE_VERSION) ? cached.latest : 'unknown';
|
|
56
54
|
}
|
|
57
|
-
// Race a probe against a timeout;
|
|
58
|
-
// update plan stays best-effort and never blocks the update itself.
|
|
55
|
+
// Race a probe against a timeout; failures resolve null so nothing blocks.
|
|
59
56
|
async function settle(work, ms) {
|
|
60
57
|
let timer;
|
|
61
58
|
try {
|
|
@@ -68,9 +65,7 @@ async function settle(work, ms) {
|
|
|
68
65
|
clearTimeout(timer);
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
|
-
//
|
|
72
|
-
// renders its own interactive UI (the delegated installer runs Clack
|
|
73
|
-
// spinners), which a concurrent outer spinner would corrupt into stray bars.
|
|
68
|
+
// Inherited stdio, so a child spinner cannot corrupt this parent's.
|
|
74
69
|
async function execInherit(cmd, args) {
|
|
75
70
|
const code = await new Promise((resolve, reject) => {
|
|
76
71
|
const child = spawn(cmd, args, { stdio: 'inherit' });
|
|
@@ -80,29 +75,30 @@ async function execInherit(cmd, args) {
|
|
|
80
75
|
if (code !== 0)
|
|
81
76
|
throw new Error(`${cmd} exited with code ${code}`);
|
|
82
77
|
}
|
|
83
|
-
// Current → latest per add-on. Every probe is capped and nullable
|
|
84
|
-
// prints `unknown` for anything unreachable
|
|
78
|
+
// Current → latest per add-on. Every probe is capped and nullable, and the
|
|
79
|
+
// plan prints `unknown` for anything unreachable.
|
|
85
80
|
async function probeUpdatePlan(cliLatest) {
|
|
86
|
-
const rtkBin =
|
|
81
|
+
const rtkBin = resolveRtkBinary();
|
|
87
82
|
const ponytailPkg = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'package.json');
|
|
88
|
-
const
|
|
83
|
+
const tersioRule = path.join(OMP_PLUGINS_DIR, 'node_modules', '@krtclcdy', 'tersio', 'extensions', 'caveman-session', 'rule.md');
|
|
84
|
+
const controller = new AbortController();
|
|
89
85
|
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),
|
|
86
|
+
settle(rtkBin ? execP(rtkBin, ['--version'], { timeout: 5000 }).then((r) => normalizeRtkVersion(r.stdout.trim() || r.stderr.trim()) || null) : Promise.resolve(null), 6000),
|
|
87
|
+
settle(httpsGet(RTK_RELEASE_API, { signal: controller.signal }).then((text) => normalizeRtkVersion(JSON.parse(text).tag_name) || null), 1500),
|
|
88
|
+
readTextIfExists(tersioRule),
|
|
89
|
+
settle(httpsGet(CAVEMAN_REMOTE_RULE, { signal: controller.signal }).then((text) => sha256Hex(text).slice(0, 8)), 1500),
|
|
94
90
|
readTextIfExists(ponytailPkg),
|
|
95
91
|
]);
|
|
96
|
-
|
|
92
|
+
controller.abort();
|
|
97
93
|
return {
|
|
98
94
|
cli: cliLatest,
|
|
99
95
|
rtk: [rtkLocal, rtkRelease],
|
|
100
|
-
rule: [
|
|
96
|
+
rule: [ruleLocalText ? sha256Hex(ruleLocalText).slice(0, 8) : null, ruleRemoteText],
|
|
101
97
|
ponytail: ponytailLocalText ? parseJsonObject(ponytailLocalText)?.version ?? null : null,
|
|
102
98
|
};
|
|
103
99
|
}
|
|
104
|
-
// Every add-on prints
|
|
105
|
-
//
|
|
100
|
+
// Every add-on prints a version jump when stale, "up to date" otherwise, and
|
|
101
|
+
// "unknown" when its source cannot be reached.
|
|
106
102
|
function planLines(plan) {
|
|
107
103
|
const stale = [];
|
|
108
104
|
const status = [];
|
|
@@ -136,12 +132,10 @@ async function runLatestUpdate() {
|
|
|
136
132
|
if (verbose)
|
|
137
133
|
forwardedArgs.push('--verbose');
|
|
138
134
|
const npmCommand = IS_WINDOWS ? process.env.ComSpec || 'cmd.exe' : 'npm';
|
|
139
|
-
//
|
|
140
|
-
// metadata cache, so a stale `@latest` can never pin an older release.
|
|
135
|
+
// `--prefer-online` beats the local cache, so a stale @latest cannot pin down.
|
|
141
136
|
const cliLatest = await latestPublishedVersion();
|
|
142
137
|
const target = cliLatest && /^\d+\.\d+\.\d+$/.test(cliLatest) ? `@${cliLatest}` : '@latest';
|
|
143
|
-
//
|
|
144
|
-
// unknown and never block the update.
|
|
138
|
+
// Best-effort: unreachable probes print as unknown.
|
|
145
139
|
const plan = await probeUpdatePlan(cliLatest);
|
|
146
140
|
const { stale, status } = planLines(plan);
|
|
147
141
|
if (dryRun) {
|
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');
|