@krtclcdy/tersio 1.0.3 → 2.0.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.
@@ -1,31 +1,23 @@
1
- import os from "node:os";
2
- import path from "node:path";
3
- import { COMBO_LEVELS, getSharedComboState, isOmpSubagentPrompt, setSharedComboMode } from "../shared/session-state.js";
4
- import { readRtkDefault } from "../shared/plugin-settings.js";
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { asPromptArray, getSharedComboState, isComboPresetActive, isOmpSubagentPrompt, lastCustomValue, normalizeInputCommand, paintStatusBar, sessionEntries, setSharedComboMode } from '../shared/session-state.js';
4
+ import { readRtkDefault } from '../shared/plugin-settings.js';
5
5
  const DEFAULT_ENABLED = false;
6
6
  function asBoolean(value) {
7
- if (typeof value === "boolean")
7
+ if (typeof value === 'boolean')
8
8
  return value;
9
- if (value === "on" || value === "true")
9
+ if (value === 'on' || value === 'true')
10
10
  return true;
11
- if (value === "off" || value === "false")
11
+ if (value === 'off' || value === 'false')
12
12
  return false;
13
13
  return null;
14
14
  }
15
15
  function resolveEnabled(entries) {
16
- if (!Array.isArray(entries))
17
- return null;
18
- for (let i = entries.length - 1; i >= 0; i -= 1) {
19
- const entry = entries[i];
20
- if (entry?.type !== "custom" || entry?.customType !== "rtk-mode")
21
- continue;
22
- return asBoolean(entry?.data?.enabled);
23
- }
24
- return null;
16
+ return lastCustomValue(entries, 'rtk-mode', (data) => asBoolean(data?.enabled));
25
17
  }
26
- const IS_WINDOWS = process.platform === "win32";
18
+ const IS_WINDOWS = process.platform === 'win32';
27
19
  const HOME = os.homedir();
28
- const RTK_BINARY = path.join(HOME, ".bun", "bin", IS_WINDOWS ? "rtk.exe" : "rtk");
20
+ const RTK_BINARY = path.join(HOME, '.bun', 'bin', IS_WINDOWS ? 'rtk.exe' : 'rtk');
29
21
  const RTK_PROMPT = `RTK mode active for this session.
30
22
  Use Rust Token Killer for shell output that would otherwise be noisy. Prefer explicit RTK commands in bash: \`rtk git status\`, \`rtk git diff\`, \`rtk read <file>\`, \`rtk grep <pattern> <path>\`, \`rtk find <glob> <path>\`, \`rtk test <cmd...>\`, \`rtk tsc\`, \`rtk lint\`, or \`rtk <tool> ...\` for supported dev commands.
31
23
  Do not use RTK when exact raw output is required, when a specialized OMP tool is required by system policy, or when the command changes state and RTK would hide important confirmation text. Specialized OMP tools still win: read/glob/grep/edit/lsp stay preferred over shell equivalents.`;
@@ -41,50 +33,43 @@ export default function rtkSessionExtension(pi) {
41
33
  if (!c?.ui?.setStatus)
42
34
  return;
43
35
  // Combo owns the bar when any preset is active; keep ours empty to avoid duplication.
44
- if (getSharedComboState().level in COMBO_LEVELS && getSharedComboState().level !== "off") {
45
- c.ui.setStatus("rtk", undefined);
46
- return;
47
- }
48
- if (!enabled) {
49
- c.ui.setStatus("rtk", undefined);
36
+ if (isComboPresetActive() || !enabled) {
37
+ c.ui.setStatus('rtk', undefined);
50
38
  return;
51
39
  }
52
- const theme = c.ui.theme;
53
- const indicator = isActive && theme?.fg ? theme.fg("accent", "⚡") : "⚡";
54
- const label = "rtk: ON";
55
- c.ui.setStatus("rtk", theme?.fg ? `${indicator} ${theme.fg("muted", label)}` : `${indicator} ${label}`);
40
+ paintStatusBar(c.ui, 'rtk', '⚡', 'rtk: ON', isActive);
56
41
  }
57
42
  function setEnabled(next, ctx) {
58
43
  enabled = Boolean(next);
59
- pi.appendEntry?.("rtk-mode", { enabled });
60
- setSharedComboMode("rtk", enabled);
44
+ pi.appendEntry?.('rtk-mode', { enabled });
45
+ setSharedComboMode('rtk', enabled);
61
46
  syncStatus(ctx);
62
- ctx?.ui?.notify?.(`RTK mode ${enabled ? "on" : "off"}.`, "info");
47
+ ctx?.ui?.notify?.(`RTK mode ${enabled ? 'on' : 'off'}.`, 'info');
63
48
  }
64
- pi.setLabel?.("RTK session toggle");
65
- pi.registerCommand?.("rtk", {
66
- description: "Toggle RTK compact shell-output guidance for this session",
49
+ pi.setLabel?.('RTK session toggle');
50
+ pi.registerCommand?.('rtk', {
51
+ description: 'Toggle RTK compact shell-output guidance for this session',
67
52
  handler: async (args, ctx) => {
68
- const arg = String(args || "").trim().toLowerCase();
69
- if (!arg || arg === "status") {
70
- ctx?.ui?.notify?.(`RTK: ${enabled ? "on" : "off"}`, "info");
53
+ const arg = String(args || '').trim().toLowerCase();
54
+ if (!arg || arg === 'status') {
55
+ ctx?.ui?.notify?.(`RTK: ${enabled ? 'on' : 'off'}`, 'info');
71
56
  return;
72
57
  }
73
- if (["on", "enable", "enabled", "true"].includes(arg)) {
58
+ if (['on', 'enable', 'enabled', 'true'].includes(arg)) {
74
59
  setEnabled(true, ctx);
75
60
  return;
76
61
  }
77
- if (["off", "disable", "disabled", "false"].includes(arg)) {
62
+ if (['off', 'disable', 'disabled', 'false'].includes(arg)) {
78
63
  setEnabled(false, ctx);
79
64
  return;
80
65
  }
81
- ctx?.ui?.notify?.("Usage: /rtk [on|off|status]", "warning");
66
+ ctx?.ui?.notify?.('Usage: /rtk [on|off|status]', 'warning');
82
67
  },
83
68
  });
84
69
  pi.registerTool?.({
85
- name: "rtk_run",
86
- label: "RTK Run",
87
- description: "Run the installed `rtk` binary for compact command output when RTK mode is enabled.",
70
+ name: 'rtk_run',
71
+ label: 'RTK Run',
72
+ description: 'Run the installed `rtk` binary for compact command output when RTK mode is enabled.',
88
73
  parameters: z.object({
89
74
  args: z.array(z.string()).min(1).describe("Arguments passed to rtk, e.g. ['git','status'] or ['read','src/index.ts']"),
90
75
  }),
@@ -92,60 +77,60 @@ export default function rtkSessionExtension(pi) {
92
77
  if (!enabled) {
93
78
  return {
94
79
  isError: true,
95
- content: [{ type: "text", text: "RTK mode is off. Run /rtk on for this session, or use bash explicitly." }],
80
+ content: [{ type: 'text', text: 'RTK mode is off. Run /rtk on for this session, or use bash explicitly.' }],
96
81
  details: { enabled },
97
82
  };
98
83
  }
99
- onUpdate?.({ content: [{ type: "text", text: `rtk ${params.args.join(" ")}` }], details: { phase: "start" } });
84
+ onUpdate?.({ content: [{ type: 'text', text: `rtk ${params.args.join(' ')}` }], details: { phase: 'start' } });
100
85
  const result = await pi.exec(RTK_BINARY, params.args, { signal, cwd: ctx?.cwd || pi.cwd });
101
- const text = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? "\n" : "");
86
+ const text = [result.stdout, result.stderr].filter(Boolean).join('\n');
102
87
  return {
103
88
  isError: result.code !== 0,
104
- content: [{ type: "text", text: text || `rtk exited ${result.code}` }],
89
+ content: [{ type: 'text', text: text || `rtk exited ${result.code}` }],
105
90
  details: { code: result.code, killed: result.killed, enabled },
106
91
  };
107
92
  },
108
93
  });
109
- pi.on("input", async (event) => {
110
- if (event?.source === "extension")
94
+ pi.on('input', async (event) => {
95
+ if (event?.source === 'extension')
111
96
  return;
112
- const t = String(event?.text || "").trim().toLowerCase().replace(/[.!?\s]+$/, "");
113
- if (t === "rtk on" || t === "use rtk")
97
+ const t = normalizeInputCommand(event?.text);
98
+ if (t === 'rtk on' || t === 'use rtk')
114
99
  setEnabled(true);
115
- if (t === "rtk off" || t === "stop rtk")
100
+ if (t === 'rtk off' || t === 'stop rtk')
116
101
  setEnabled(false);
117
102
  });
118
103
  function restoreEnabled(ctx) {
119
- const entries = ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
104
+ const entries = sessionEntries(ctx);
120
105
  // Persisted session state wins; a fresh session falls back to the
121
106
  // installer/user-configured default (off unless configured).
122
107
  const persisted = resolveEnabled(entries);
123
- enabled = typeof persisted === "boolean" ? persisted : readRtkDefault();
108
+ enabled = typeof persisted === 'boolean' ? persisted : readRtkDefault();
124
109
  syncStatus(ctx);
125
110
  }
126
- pi.on("session_start", async (_event, ctx) => {
111
+ pi.on('session_start', async (_event, ctx) => {
127
112
  restoreEnabled(ctx);
128
- ctx?.ui?.notify?.(`RTK loaded: ${enabled ? "on" : "off"}`, "info");
113
+ ctx?.ui?.notify?.(`RTK loaded: ${enabled ? 'on' : 'off'}`, 'info');
129
114
  });
130
- pi.on("session_branch", async (_event, ctx) => {
115
+ pi.on('session_branch', async (_event, ctx) => {
131
116
  restoreEnabled(ctx);
132
117
  });
133
- pi.on("session_tree", async (_event, ctx) => {
118
+ pi.on('session_tree', async (_event, ctx) => {
134
119
  restoreEnabled(ctx);
135
120
  });
136
- pi.on("agent_start", async (_event, ctx) => {
121
+ pi.on('agent_start', async (_event, ctx) => {
137
122
  isActive = true;
138
123
  syncStatus(ctx);
139
124
  });
140
- pi.on("agent_end", async (_event, ctx) => {
125
+ pi.on('agent_end', async (_event, ctx) => {
141
126
  isActive = false;
142
127
  syncStatus(ctx);
143
128
  });
144
- pi.on("before_agent_start", async (event) => {
145
- const active = isOmpSubagentPrompt(event.systemPrompt) ? getSharedComboState().rtk === "on" : enabled;
129
+ pi.on('before_agent_start', async (event) => {
130
+ const active = isOmpSubagentPrompt(event.systemPrompt) ? getSharedComboState().rtk === 'on' : enabled;
146
131
  if (!active)
147
132
  return;
148
- const base = Array.isArray(event.systemPrompt) ? event.systemPrompt : [event.systemPrompt];
133
+ const base = asPromptArray(event.systemPrompt);
149
134
  return { systemPrompt: [...base, RTK_PROMPT] };
150
135
  });
151
136
  }
@@ -1,28 +1,25 @@
1
- import { reconcileSharedComboEntries } from "./session-state.js";
2
- const MARKER = "SUPREME TOKEN SAVER MODES ACTIVE";
3
- function entriesFrom(ctx) {
4
- return ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
5
- }
1
+ import { asPromptArray, reconcileSharedComboEntries, sessionEntries, systemPromptIncludes } from './session-state.js';
2
+ const MARKER = 'SUPREME TOKEN SAVER MODES ACTIVE';
6
3
  function instruction(state) {
7
4
  const modes = [
8
- state.caveman !== "off" && `caveman=${state.caveman}`,
9
- state.rtk === "on" && "rtk=on",
10
- state.ponytail !== "off" && `ponytail=${state.ponytail}`,
5
+ state.caveman !== 'off' && `caveman=${state.caveman}`,
6
+ state.rtk === 'on' && 'rtk=on',
7
+ state.ponytail !== 'off' && `ponytail=${state.ponytail}`,
11
8
  ].filter(Boolean);
12
9
  if (!modes.length)
13
10
  return null;
14
- 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.`;
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.`;
15
12
  }
16
13
  export default function modeReinforcementExtension(pi) {
17
- pi.setLabel?.("Tersio mode reinforcement");
18
- pi.on("before_agent_start", async (event, ctx) => {
14
+ pi.setLabel?.('Tersio mode reinforcement');
15
+ pi.on('before_agent_start', async (event, ctx) => {
19
16
  if (!ctx?.hasUI)
20
17
  return;
21
- const text = instruction(reconcileSharedComboEntries(entriesFrom(ctx)));
18
+ const text = instruction(reconcileSharedComboEntries(sessionEntries(ctx)));
22
19
  if (!text)
23
20
  return;
24
- const base = Array.isArray(event.systemPrompt) ? event.systemPrompt : [event.systemPrompt];
25
- if (base.some((prompt) => typeof prompt === "string" && prompt.includes(MARKER)))
21
+ const base = asPromptArray(event.systemPrompt);
22
+ if (systemPromptIncludes(base, MARKER))
26
23
  return;
27
24
  return { systemPrompt: [...base, text] };
28
25
  });
@@ -3,15 +3,15 @@
3
3
  // written by `omp plugin config set @krtclcdy/tersio <key> <value>` and by
4
4
  // the installer profile step. Tolerant: any parse failure yields {} so every
5
5
  // caller falls back to its own default.
6
- import { existsSync, readFileSync } from "node:fs";
7
- import os from "node:os";
8
- import path from "node:path";
9
- export const PLUGIN_NAME = "@krtclcdy/tersio";
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ export const PLUGIN_NAME = '@krtclcdy/tersio';
10
10
  function lockPaths() {
11
- const configHome = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
11
+ const configHome = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
12
12
  return [
13
- path.join(os.homedir(), ".omp", "plugins", "omp-plugins.lock.json"),
14
- path.join(configHome, "omp", "plugins", "omp-plugins.lock.json"),
13
+ path.join(os.homedir(), '.omp', 'plugins', 'omp-plugins.lock.json'),
14
+ path.join(configHome, 'omp', 'plugins', 'omp-plugins.lock.json'),
15
15
  ];
16
16
  }
17
17
  // `settings[PLUGIN_NAME]` in the lock file; empty object when missing.
@@ -20,26 +20,28 @@ export function readPluginSettings() {
20
20
  if (!existsSync(p))
21
21
  continue;
22
22
  try {
23
- const config = JSON.parse(readFileSync(p, "utf8"));
23
+ const config = JSON.parse(readFileSync(p, 'utf8'));
24
24
  const values = config.settings?.[PLUGIN_NAME];
25
- if (values && typeof values === "object" && !Array.isArray(values))
25
+ if (values && typeof values === 'object' && !Array.isArray(values))
26
26
  return values;
27
27
  }
28
28
  catch { /* tolerate corrupt file */ }
29
29
  }
30
30
  return {};
31
31
  }
32
- const COMBO_LEVELS = new Set(["off", "medium", "balanced", "max"]);
32
+ const COMBO_LEVELS = new Set(['off', 'medium', 'balanced', 'max']);
33
+ const CAVEMAN_MODES = new Set(['off', 'lite', 'full', 'ultra', 'wenyan']);
34
+ function readStringDefault(key, valid) {
35
+ const raw = readPluginSettings()[key];
36
+ return typeof raw === 'string' && valid.has(raw) ? raw : 'off';
37
+ }
33
38
  export function readComboDefault() {
34
- const raw = readPluginSettings().comboDefault;
35
- return typeof raw === "string" && COMBO_LEVELS.has(raw) ? raw : "off";
39
+ return readStringDefault('comboDefault', COMBO_LEVELS);
36
40
  }
37
- const CAVEMAN_MODES = new Set(["off", "lite", "full", "ultra", "wenyan"]);
38
41
  export function readCavemanDefault() {
39
- const raw = readPluginSettings().cavemanDefault;
40
- return typeof raw === "string" && CAVEMAN_MODES.has(raw) ? raw : "off";
42
+ return readStringDefault('cavemanDefault', CAVEMAN_MODES);
41
43
  }
42
44
  export function readRtkDefault() {
43
45
  const raw = readPluginSettings().rtkDefault;
44
- return typeof raw === "boolean" ? raw : false;
46
+ return typeof raw === 'boolean' ? raw : false;
45
47
  }
@@ -1,41 +1,49 @@
1
- const BRIDGE_KEY = Symbol.for("tersio/combo-session-state");
2
- export const OMP_SUBAGENT_MARKER = "You are operating on a piece of work assigned to you by the main agent.";
1
+ const BRIDGE_KEY = Symbol.for('tersio/combo-session-state');
2
+ export const OMP_SUBAGENT_MARKER = 'You are operating on a piece of work assigned to you by the main agent.';
3
3
  export const COMBO_LEVELS = Object.freeze({
4
- off: Object.freeze({ level: "off", caveman: "off", rtk: "off", ponytail: "off" }),
5
- medium: Object.freeze({ level: "medium", caveman: "lite", rtk: "on", ponytail: "lite" }),
6
- balanced: Object.freeze({ level: "balanced", caveman: "full", rtk: "on", ponytail: "full" }),
7
- max: Object.freeze({ level: "max", caveman: "ultra", rtk: "on", ponytail: "ultra" }),
4
+ off: Object.freeze({ level: 'off', caveman: 'off', rtk: 'off', ponytail: 'off' }),
5
+ medium: Object.freeze({ level: 'medium', caveman: 'lite', rtk: 'on', ponytail: 'lite' }),
6
+ balanced: Object.freeze({ level: 'balanced', caveman: 'full', rtk: 'on', ponytail: 'full' }),
7
+ max: Object.freeze({ level: 'max', caveman: 'ultra', rtk: 'on', ponytail: 'ultra' }),
8
8
  });
9
9
  const MODE_VALUES = {
10
- caveman: new Set(["off", "lite", "full", "ultra", "wenyan"]),
11
- rtk: new Set(["off", "on"]),
12
- ponytail: new Set(["off", "lite", "full", "ultra", "review"]),
10
+ caveman: new Set(['off', 'lite', 'full', 'ultra', 'wenyan']),
11
+ rtk: new Set(['off', 'on']),
12
+ ponytail: new Set(['off', 'lite', 'full', 'ultra', 'review']),
13
13
  };
14
- function normalizeMode(name, value) {
15
- if (name === "rtk" && typeof value === "boolean")
16
- return value ? "on" : "off";
17
- const mode = String(value ?? "").trim().toLowerCase();
14
+ const MODE_ENTRY_TYPES = {
15
+ 'caveman-mode': 'caveman',
16
+ 'rtk-mode': 'rtk',
17
+ 'ponytail-mode': 'ponytail',
18
+ };
19
+ export function normalizeMode(name, value) {
20
+ if (name === 'rtk' && typeof value === 'boolean')
21
+ return value ? 'on' : 'off';
22
+ const mode = String(value ?? '').trim().toLowerCase();
18
23
  return MODE_VALUES[name]?.has(mode) ? mode : null;
19
24
  }
20
- function deriveLevel(modes) {
21
- for (const level of ["off", "medium", "max"]) {
25
+ export function deriveLevel(modes) {
26
+ for (const level of Object.keys(COMBO_LEVELS)) {
22
27
  const preset = COMBO_LEVELS[level];
23
- if (preset.caveman === modes.caveman && preset.rtk === modes.rtk && preset.ponytail === modes.ponytail)
28
+ if (preset.caveman === modes?.caveman && preset.rtk === modes?.rtk && preset.ponytail === modes?.ponytail)
24
29
  return level;
25
30
  }
26
- return "custom";
31
+ return 'custom';
32
+ }
33
+ function isPresetLevel(value) {
34
+ return Object.prototype.hasOwnProperty.call(COMBO_LEVELS, value);
27
35
  }
28
36
  function isKnownLevel(value) {
29
- return value === "custom" || Object.prototype.hasOwnProperty.call(COMBO_LEVELS, value);
37
+ return value === 'custom' || isPresetLevel(value);
30
38
  }
31
39
  function levelForIndividualModes(modes) {
32
- return modes.caveman === "off" && modes.rtk === "off" && modes.ponytail === "off" ? "off" : "custom";
40
+ return modes.caveman === 'off' && modes.rtk === 'off' && modes.ponytail === 'off' ? 'off' : 'custom';
33
41
  }
34
42
  function normalizedState(modes, level = deriveLevel(modes)) {
35
43
  const state = {
36
- caveman: normalizeMode("caveman", modes?.caveman) || "off",
37
- rtk: normalizeMode("rtk", modes?.rtk) || "off",
38
- ponytail: normalizeMode("ponytail", modes?.ponytail) || "off",
44
+ caveman: normalizeMode('caveman', modes?.caveman) || 'off',
45
+ rtk: normalizeMode('rtk', modes?.rtk) || 'off',
46
+ ponytail: normalizeMode('ponytail', modes?.ponytail) || 'off',
39
47
  };
40
48
  return Object.freeze({ level: isKnownLevel(level) ? level : deriveLevel(state), ...state });
41
49
  }
@@ -52,19 +60,54 @@ function publish(state) {
52
60
  shared.listener?.(state);
53
61
  return state;
54
62
  }
63
+ export function normalizeInputCommand(value) {
64
+ return String(value || '').trim().toLowerCase().replace(/[.!?\s]+$/, '');
65
+ }
66
+ export function asPromptArray(systemPrompt) {
67
+ return Array.isArray(systemPrompt) ? systemPrompt : [systemPrompt];
68
+ }
69
+ export function systemPromptIncludes(systemPrompt, marker) {
70
+ return asPromptArray(systemPrompt).some((prompt) => typeof prompt === 'string' && prompt.includes(marker));
71
+ }
55
72
  export function isOmpSubagentPrompt(systemPrompt) {
56
- const prompts = Array.isArray(systemPrompt) ? systemPrompt : [systemPrompt];
57
- return prompts.some((prompt) => typeof prompt === "string" && prompt.includes(OMP_SUBAGENT_MARKER));
73
+ return systemPromptIncludes(systemPrompt, OMP_SUBAGENT_MARKER);
58
74
  }
59
75
  export function normalizeComboLevel(value) {
60
- const level = String(value || "").trim().toLowerCase();
61
- return Object.prototype.hasOwnProperty.call(COMBO_LEVELS, level) ? level : null;
76
+ const level = String(value || '').trim().toLowerCase();
77
+ return isPresetLevel(level) ? level : null;
78
+ }
79
+ export function paintStatusBar(ui, key, emoji, label, isActive) {
80
+ const theme = ui?.theme;
81
+ const indicator = isActive && theme?.fg ? theme.fg('accent', emoji) : emoji;
82
+ ui?.setStatus?.(key, theme?.fg ? `${indicator} ${theme.fg('muted', label)}` : `${indicator} ${label}`);
83
+ }
84
+ // Last-wins scan for a custom session entry; skips entries whose value fails
85
+ // to parse so a corrupt write never shadows an older valid one.
86
+ export function lastCustomValue(entries, customType, pick) {
87
+ if (!Array.isArray(entries))
88
+ return null;
89
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
90
+ const entry = entries[i];
91
+ if (entry?.type !== 'custom' || entry?.customType !== customType)
92
+ continue;
93
+ const value = pick(entry?.data);
94
+ if (value !== null && value !== undefined)
95
+ return value;
96
+ }
97
+ return null;
98
+ }
99
+ export function sessionEntries(ctx) {
100
+ return ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || [];
62
101
  }
63
102
  export function getSharedComboState() {
64
103
  return bridge().state;
65
104
  }
105
+ export function isComboPresetActive() {
106
+ const level = getSharedComboState().level;
107
+ return level !== 'off' && isPresetLevel(level);
108
+ }
66
109
  export function setSharedComboLevel(value) {
67
- const level = normalizeComboLevel(value) || "off";
110
+ const level = normalizeComboLevel(value) || 'off';
68
111
  return publish(normalizedState(COMBO_LEVELS[level], level));
69
112
  }
70
113
  export function setSharedComboMode(name, value) {
@@ -76,12 +119,12 @@ export function setSharedComboMode(name, value) {
76
119
  }
77
120
  export function reconcileSharedComboEntries(entries) {
78
121
  let modes = { ...COMBO_LEVELS.off };
79
- let level = "off";
122
+ let level = 'off';
80
123
  if (Array.isArray(entries)) {
81
124
  for (const entry of entries) {
82
- if (entry?.type !== "custom")
125
+ if (entry?.type !== 'custom')
83
126
  continue;
84
- if (entry.customType === "combo-level") {
127
+ if (entry.customType === 'combo-level') {
85
128
  const preset = normalizeComboLevel(entry?.data?.level);
86
129
  if (preset) {
87
130
  modes = { ...COMBO_LEVELS[preset] };
@@ -89,16 +132,10 @@ export function reconcileSharedComboEntries(entries) {
89
132
  }
90
133
  continue;
91
134
  }
92
- const name = entry.customType === "caveman-mode"
93
- ? "caveman"
94
- : entry.customType === "rtk-mode"
95
- ? "rtk"
96
- : entry.customType === "ponytail-mode"
97
- ? "ponytail"
98
- : null;
135
+ const name = MODE_ENTRY_TYPES[entry.customType ?? ''] ?? null;
99
136
  if (!name)
100
137
  continue;
101
- const value = name === "rtk" ? entry?.data?.enabled : entry?.data?.mode;
138
+ const value = name === 'rtk' ? entry?.data?.enabled : entry?.data?.mode;
102
139
  const mode = normalizeMode(name, value);
103
140
  if (mode) {
104
141
  modes[name] = mode;
@@ -109,13 +146,8 @@ export function reconcileSharedComboEntries(entries) {
109
146
  return publish(normalizedState(modes, level));
110
147
  }
111
148
  export function setSharedComboListener(listener) {
112
- const shared = bridge();
113
- shared.listener = typeof listener === "function" ? listener : null;
114
- return () => {
115
- if (shared.listener === listener)
116
- shared.listener = null;
117
- };
149
+ bridge().listener = typeof listener === 'function' ? listener : null;
118
150
  }
119
151
  export function resetSharedComboState() {
120
- return setSharedComboLevel("off");
152
+ return setSharedComboLevel('off');
121
153
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@krtclcdy/tersio",
3
- "version": "1.0.3",
4
- "description": "Amanai reward detector and three toggleable OMP extensions for terse replies, compact shell output, and minimal code decisions \u2014 with a manual updater and dry-run support.",
3
+ "version": "2.0.0",
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",
7
7
  "tersio",
@@ -11,9 +11,7 @@
11
11
  "caveman-mode",
12
12
  "rtk-rust-token-killer",
13
13
  "ponytail-omp",
14
- "extensions",
15
- "amanai-reward-detector",
16
- "pi-package"
14
+ "extensions"
17
15
  ],
18
16
  "license": "MIT",
19
17
  "author": "KurutoDenzeru",
@@ -31,10 +29,8 @@
31
29
  },
32
30
  "omp": {
33
31
  "name": "Tersio",
34
- "description": "Amanai reward detector plus toggleable Caveman/RTK/Ponytail session modes with Combo presets",
35
- "extensions": [
36
- "./extensions/amanai-reward/index.js"
37
- ],
32
+ "description": "Toggleable Caveman/RTK/Ponytail session modes with Combo presets",
33
+ "extensions": [],
38
34
  "features": {
39
35
  "caveman": {
40
36
  "description": "Caveman terse-reply session mode (/caveman)",
@@ -109,11 +105,6 @@
109
105
  }
110
106
  }
111
107
  },
112
- "pi": {
113
- "extensions": [
114
- "./extensions/amanai-reward/pi.js"
115
- ]
116
- },
117
108
  "files": [
118
109
  "tersio.js",
119
110
  "extensions/**/*.js"
@@ -125,7 +116,7 @@
125
116
  "check": "tsc --noEmit",
126
117
  "doctor": "node tersio.js --doctor",
127
118
  "dry-run": "node tersio.js --dry-run --scope user --yes",
128
- "test": "tsx --test test/*.test.ts"
119
+ "test": "tsx --test test/*.test.ts test/*/*.test.ts"
129
120
  },
130
121
  "engines": {
131
122
  "node": ">=18"