@krtclcdy/tersio 2.23.0 → 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.
Files changed (55) hide show
  1. package/README.md +58 -45
  2. package/cli/agent-hosts.js +42 -0
  3. package/cli/agents.js +266 -0
  4. package/cli/common.js +16 -20
  5. package/cli/currency.js +8 -12
  6. package/cli/dashboard.js +49 -37
  7. package/cli/doctor-fix.js +28 -17
  8. package/cli/doctor.js +52 -41
  9. package/cli/hosts.js +118 -0
  10. package/cli/install.js +180 -117
  11. package/cli/interactive.js +27 -1
  12. package/cli/layer.js +24 -0
  13. package/cli/manifest.js +36 -0
  14. package/cli/omp-layer.js +51 -0
  15. package/cli/pi-layer.js +37 -0
  16. package/cli/pi-wiring.js +92 -0
  17. package/cli/profile.js +44 -46
  18. package/cli/reset.js +3 -26
  19. package/cli/rtk-wiring.js +10 -15
  20. package/cli/uninstall.js +135 -44
  21. package/cli/update.js +12 -19
  22. package/dashboard/dist/index.html +16 -16
  23. package/extensions/ai-addons-updater/index.js +31 -24
  24. package/extensions/ai-addons-updater/index.ts +32 -32
  25. package/extensions/caveman-session/index.js +6 -6
  26. package/extensions/caveman-session/index.ts +6 -6
  27. package/extensions/combo-toggle/index.js +42 -40
  28. package/extensions/combo-toggle/index.ts +36 -47
  29. package/extensions/lib/utils.js +36 -9
  30. package/extensions/lib/utils.ts +37 -9
  31. package/extensions/rtk-session/index.js +9 -9
  32. package/extensions/rtk-session/index.ts +9 -14
  33. package/extensions/shared/carbon.js +5 -8
  34. package/extensions/shared/carbon.ts +5 -8
  35. package/extensions/shared/host.js +68 -0
  36. package/extensions/shared/host.ts +104 -0
  37. package/extensions/shared/omp-prompt.js +12 -0
  38. package/extensions/shared/plugin-settings.js +43 -30
  39. package/extensions/shared/plugin-settings.ts +45 -26
  40. package/extensions/shared/pricing.js +26 -15
  41. package/extensions/shared/pricing.ts +28 -16
  42. package/extensions/shared/rtk-gain.js +11 -22
  43. package/extensions/shared/rtk-gain.ts +11 -22
  44. package/extensions/shared/session-state.js +21 -25
  45. package/extensions/shared/session-state.ts +22 -26
  46. package/extensions/shared/types.ts +10 -3
  47. package/extensions/shared/usage-ledger.js +24 -36
  48. package/extensions/shared/usage-ledger.ts +29 -50
  49. package/extensions/shared/usage-store.js +14 -12
  50. package/extensions/shared/usage-store.ts +16 -14
  51. package/extensions/tersio-commands/index.js +2 -1
  52. package/extensions/tersio-commands/index.ts +2 -1
  53. package/package.json +4 -2
  54. package/tersio.js +4 -4
  55. package/extensions/shared/mode-reinforcement.js +0 -26
@@ -1,11 +1,9 @@
1
1
  // extensions/shared/usage-store.ts — tersio-owned usage.db.
2
- // Persists the same per-message rows importSessionTokens derives live (model,
3
- // tokens, cache, cost input, timing, status, tools), so top models, costing,
4
- // cache, CO2 inputs, and activity survive session-file rotation. Sync is
5
- // incremental: a files ledger (mtime+size) skips unchanged transcripts, and
6
- // every read applies the current reset watermark — the store is a cache,
7
- // never a fork. Missing sqlite3 CLI → sync false / read null, callers fall
8
- // back to the live path. Never touches RTK's history.db or host transcripts.
2
+ // Persists the rows importSessionTokens derives live, so reports survive
3
+ // session-file rotation. Sync is incremental (a files ledger skips unchanged
4
+ // transcripts) and every read applies the reset watermark, so the store is a
5
+ // cache, never a fork. Missing sqlite3 → sync false / read null. Never touches
6
+ // RTK's history.db or host transcripts.
9
7
  import { execFileSync } from 'node:child_process';
10
8
  import fs from 'node:fs';
11
9
  import os from 'node:os';
@@ -23,6 +21,7 @@ import {
23
21
  walkJsonl,
24
22
  } from './usage-ledger.ts';
25
23
  import { tersioDataPath } from '../lib/utils.ts';
24
+ import { MODEL_ALIASES } from './pricing.ts';
26
25
  import type { RunStatus, SessionTokens } from './usage-ledger.ts';
27
26
 
28
27
  export function usageDbPath(): string {
@@ -70,6 +69,10 @@ function query(db: string, sql: string): string[][] {
70
69
 
71
70
  function ensureSchema(db: string): void {
72
71
  fs.mkdirSync(path.dirname(db), { recursive: true });
72
+ // Rows imported before an alias existed keep the spelling they were stored
73
+ // with, and the mtime ledger will not re-read those transcripts. Fold them in
74
+ // once, so the merge shows up without a reset.
75
+ const rekeys = MODEL_ALIASES.map((a) => `UPDATE messages SET model='${a.id}' WHERE model='${a.feed}';`).join('');
73
76
  run(
74
77
  db,
75
78
  `CREATE TABLE IF NOT EXISTS meta (k TEXT PRIMARY KEY, v TEXT NOT NULL);` +
@@ -77,7 +80,7 @@ function ensureSchema(db: string): void {
77
80
  `CREATE TABLE IF NOT EXISTS messages (file TEXT NOT NULL, t REAL, model TEXT NOT NULL,` +
78
81
  ` i INTEGER NOT NULL, o INTEGER NOT NULL, d REAL, cr INTEGER NOT NULL, cw INTEGER NOT NULL,` +
79
82
  ` usd REAL, st TEXT NOT NULL, code REAL, note TEXT, tools TEXT NOT NULL DEFAULT '[]');` +
80
- `CREATE INDEX IF NOT EXISTS idx_messages_file ON messages(file);`,
83
+ `CREATE INDEX IF NOT EXISTS idx_messages_file ON messages(file);` + rekeys,
81
84
  );
82
85
  }
83
86
 
@@ -91,8 +94,8 @@ function readFiles(db: string): Record<string, { mtime: number; size: number }>
91
94
  return known;
92
95
  }
93
96
 
94
- // One parsed assistant message, as stored. `t` is epoch ms or null when the
95
- // source row carries no usable timestamp (live counts it, skips its recent).
97
+ // One parsed assistant message, as stored. `t` is null when the source row has
98
+ // no usable timestamp: counted, but skipped in the recent list.
96
99
  interface StoredRow {
97
100
  t: number | null;
98
101
  model: string;
@@ -173,10 +176,9 @@ function insertSql(file: string, r: StoredRow): string {
173
176
  `${nullNum(r.code)},${nullStr(r.note)},${esc(JSON.stringify(r.tools))});`;
174
177
  }
175
178
 
176
- // Incremental sync: unchanged transcripts are skipped via mtime+size,
177
- // changed ones are deleted and re-inserted. Rows for deleted transcripts
178
- // are kept, so OMP session rotation never erases history. True on success
179
- // (including nothing-to-do), false when sqlite3 or disk is unavailable.
179
+ // Incremental sync: unchanged transcripts are skipped via mtime+size, changed
180
+ // ones re-inserted. Rows for deleted transcripts are kept, so rotation never
181
+ // erases history. False when sqlite3 or disk is unavailable.
180
182
  export function syncUsageDb(): boolean {
181
183
  let db: string;
182
184
  try {
@@ -4,6 +4,7 @@
4
4
  // publishes sync sibling mirrors live, so switches notify and take effect
5
5
  // next turn — no reload.
6
6
  import { getSharedComboState, reconcileSharedComboEntries, sessionEntries, } from '../shared/session-state.js';
7
+ import { setExtensionLabel } from '../shared/host.js';
7
8
  import os from 'node:os';
8
9
  import path from 'node:path';
9
10
  import { appendUsage, readUsage } from '../shared/usage-ledger.js';
@@ -48,7 +49,7 @@ async function openDashboard(pi, ctx) {
48
49
  }
49
50
  }
50
51
  export default function tersioCommandsExtension(pi) {
51
- pi.setLabel?.('Tersio unified root command');
52
+ setExtensionLabel(pi, 'Tersio unified root command');
52
53
  pi.registerCommand?.('tersio', {
53
54
  description: 'Tersio root: status|check|update|dashboard|usage|help',
54
55
  handler: async (args, ctx) => {
@@ -8,6 +8,7 @@ import {
8
8
  reconcileSharedComboEntries,
9
9
  sessionEntries,
10
10
  } from '../shared/session-state.ts';
11
+ import { setExtensionLabel } from '../shared/host.ts';
11
12
  import os from 'node:os';
12
13
  import path from 'node:path';
13
14
  import { appendUsage, readUsage } from '../shared/usage-ledger.ts';
@@ -54,7 +55,7 @@ async function openDashboard(pi: ExtensionApi, ctx?: ExtensionCtx): Promise<void
54
55
  }
55
56
 
56
57
  export default function tersioCommandsExtension(pi: ExtensionApi): void {
57
- pi.setLabel?.('Tersio unified root command');
58
+ setExtensionLabel(pi, 'Tersio unified root command');
58
59
 
59
60
 
60
61
  pi.registerCommand?.('tersio', {
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@krtclcdy/tersio",
3
- "version": "2.23.0",
4
- "description": "✂️ Token-saving OMP add-ons: terse Caveman replies, compact RTK shell output, lean Ponytail code calls — one-command combo presets.",
3
+ "version": "2.24.0",
4
+ "description": "\u2702\ufe0f Token-saving OMP add-ons: terse Caveman replies, compact RTK shell output, lean Ponytail code calls \u2014 one-command combo presets.",
5
5
  "keywords": [
6
6
  "omp",
7
+ "pi",
8
+ "pi-package",
7
9
  "token-saving",
8
10
  "ai-tools",
9
11
  "developer-tools",
package/tersio.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // tersio.ts — Install Tersio (caveman/rtk/ponytail) add-ons on any OMP device.
3
- // Usage: node tersio.js [install|update|reinstall|doctor|dashboard|uninstall|version|help] [options]
3
+ // Usage: node tersio.js [install|update|doctor|dashboard|uninstall|version|help] [options]
4
4
  // Requires: node/npm and omp CLI
5
5
  import { PACKAGE_BIN, PACKAGE_VERSION, applyUpdate, commandArg, dashboard, dashboardExport, dashboardOpen, dashboardPort, doctor, reset, settings, showHelp, showVersion, uninstall, unknownCommand, update, usage, } from './cli/common.js';
6
6
  import { closeRL } from './cli/interactive.js';
@@ -16,9 +16,8 @@ function printHelp() {
16
16
  console.log(`Usage: ${PACKAGE_BIN} [command] [options]
17
17
 
18
18
  Commands:
19
- install Install the add-ons (user scope: all OMP sessions)
19
+ install Install the add-ons for one agent (--host omp|pi, or ask at a terminal)
20
20
  update Refresh the CLI and add-ons (RTK binary, Caveman rule, Ponytail)
21
- reinstall Clean and reinstall the user-scope add-ons
22
21
  doctor Check the current installation (--fix repairs, --dry-run previews)
23
22
  usage Ledger-backed usage + savings report
24
23
  dashboard Open the Dashboard (localhost only)
@@ -31,8 +30,9 @@ Commands:
31
30
  Options:
32
31
  --fix (doctor: repairs all; --fix=<scope> repairs one of extensions, registrations, rtk, ponytail, cli)
33
32
  --scope user (legacy; accepted and ignored — user scope is the only scope)
33
+ --host omp|pi (install|uninstall: target agent; a terminal asks instead)
34
34
  --keep-ponytail (uninstall: keep the bundled Ponytail copy — removed by default)
35
- --remove-rtk (uninstall: also remove the RTK binary)
35
+ --remove-rtk (uninstall: also remove the RTK binary; its OMP wiring always goes)
36
36
  --combo-default off|medium|balanced|max (implies caveman, rtk, ponytail)
37
37
  --caveman-default off|lite|full|ultra|wenyan-lite|wenyan-full|wenyan-ultra (override; default follows combo)
38
38
  --ponytail-default off|lite|full|ultra (override; default follows combo)
@@ -1,26 +0,0 @@
1
- import { asPromptArray, reconcileSharedComboEntries, sessionEntries, systemPromptIncludes } from './session-state.js';
2
- const MARKER = 'SUPREME TOKEN SAVER MODES ACTIVE';
3
- function instruction(state) {
4
- const modes = [
5
- state.caveman !== 'off' && `caveman=${state.caveman}`,
6
- state.rtk === 'on' && 'rtk=on',
7
- state.ponytail !== 'off' && `ponytail=${state.ponytail}`,
8
- ].filter(Boolean);
9
- if (!modes.length)
10
- return null;
11
- return `${MARKER}: ${modes.join(' · ')}. Keep these active for the entire response: concise Caveman prose, RTK for eligible noisy shell output, and the smallest correct Ponytail solution. Do not weaken or disable a mode unless the user explicitly asks.`;
12
- }
13
- export default function modeReinforcementExtension(pi) {
14
- pi.setLabel?.('Tersio mode reinforcement');
15
- pi.on('before_agent_start', async (event, ctx) => {
16
- if (!ctx?.hasUI)
17
- return;
18
- const text = instruction(reconcileSharedComboEntries(sessionEntries(ctx)));
19
- if (!text)
20
- return;
21
- const base = asPromptArray(event.systemPrompt);
22
- if (systemPromptIncludes(base, MARKER))
23
- return;
24
- return { systemPrompt: [...base, text] };
25
- });
26
- }