@krtclcdy/tersio 1.0.2 → 1.0.4
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/extensions/combo-toggle/index.js +12 -6
- package/package.json +14 -2
- package/tersio.js +115 -17
|
@@ -63,6 +63,16 @@ export default function comboToggleExtension(pi) {
|
|
|
63
63
|
c.ui.setStatus("rtk", undefined);
|
|
64
64
|
c.ui.setStatus("ponytail", undefined);
|
|
65
65
|
}
|
|
66
|
+
// ponytail: same persistence as /combo — siblings (incl. upstream ponytail)
|
|
67
|
+
// restore from these entries, so the fallback must write them too or the
|
|
68
|
+
// preset evaporates on resume and ponytail never activates.
|
|
69
|
+
function persistPreset(level) {
|
|
70
|
+
const modes = COMBO_LEVELS[level];
|
|
71
|
+
pi.appendEntry?.("caveman-mode", { mode: modes.caveman });
|
|
72
|
+
pi.appendEntry?.("rtk-mode", { enabled: modes.rtk === "on" });
|
|
73
|
+
pi.appendEntry?.("ponytail-mode", { mode: modes.ponytail });
|
|
74
|
+
pi.appendEntry?.("combo-level", { level });
|
|
75
|
+
}
|
|
66
76
|
function useState(state, ctx) {
|
|
67
77
|
currentState = state;
|
|
68
78
|
syncStatus(ctx);
|
|
@@ -99,12 +109,7 @@ export default function comboToggleExtension(pi) {
|
|
|
99
109
|
ctx?.ui?.notify?.(`Unknown combo level: ${arg}. Use: off | medium | balanced | max`, "warning");
|
|
100
110
|
return;
|
|
101
111
|
}
|
|
102
|
-
|
|
103
|
-
// Persist per-extension state so they restore on session_start
|
|
104
|
-
pi.appendEntry?.("caveman-mode", { mode: modes.caveman });
|
|
105
|
-
pi.appendEntry?.("rtk-mode", { enabled: modes.rtk === "on" });
|
|
106
|
-
pi.appendEntry?.("ponytail-mode", { mode: modes.ponytail });
|
|
107
|
-
pi.appendEntry?.("combo-level", { level });
|
|
112
|
+
persistPreset(level);
|
|
108
113
|
useState(setSharedComboLevel(level), ctx);
|
|
109
114
|
ctx?.ui?.notify?.(`Combo ${level} applied: ${levelSummary(currentState)}`, "info");
|
|
110
115
|
if (ctx?.reload)
|
|
@@ -122,6 +127,7 @@ export default function comboToggleExtension(pi) {
|
|
|
122
127
|
if (getSharedComboState().level === "off" && !(ctx?.sessionManager?.getBranch?.() || ctx?.sessionManager?.getEntries?.() || []).length) {
|
|
123
128
|
const fallback = readComboDefault();
|
|
124
129
|
if (fallback !== "off") {
|
|
130
|
+
persistPreset(fallback);
|
|
125
131
|
useState(setSharedComboLevel(fallback), ctx);
|
|
126
132
|
ctx?.ui?.notify?.(`Combo default applied: ${fallback}`, "info");
|
|
127
133
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krtclcdy/tersio",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Amanai reward detector and three toggleable OMP extensions for terse replies, compact shell output, and minimal code decisions
|
|
3
|
+
"version": "1.0.4",
|
|
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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"omp",
|
|
7
7
|
"tersio",
|
|
@@ -94,6 +94,18 @@
|
|
|
94
94
|
"type": "boolean",
|
|
95
95
|
"description": "RTK mode applied on session start when no session state exists",
|
|
96
96
|
"default": false
|
|
97
|
+
},
|
|
98
|
+
"ponytailDefault": {
|
|
99
|
+
"type": "enum",
|
|
100
|
+
"description": "Ponytail mode applied on session start when no session state exists (follows combo preset unless overridden)",
|
|
101
|
+
"values": [
|
|
102
|
+
"off",
|
|
103
|
+
"lite",
|
|
104
|
+
"full",
|
|
105
|
+
"ultra",
|
|
106
|
+
"review"
|
|
107
|
+
],
|
|
108
|
+
"default": "off"
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
},
|
package/tersio.js
CHANGED
|
@@ -19,6 +19,14 @@ const { version: PACKAGE_VERSION } = createRequire(import.meta.url)("./package.j
|
|
|
19
19
|
// Session-start mode defaults for fresh installs.
|
|
20
20
|
const COMBO_DEFAULTS = { off: true, medium: true, balanced: true, max: true };
|
|
21
21
|
const CAVEMAN_DEFAULTS = { off: true, lite: true, full: true, ultra: true, wenyan: true };
|
|
22
|
+
// ponytail: Combo preset implies all three modes. Mirrors COMBO_LEVELS in
|
|
23
|
+
// extensions/shared/session-state.ts (rtk as boolean here). Single source.
|
|
24
|
+
const COMBO_PRESET_MODES = {
|
|
25
|
+
off: { caveman: "off", rtk: false, ponytail: "off" },
|
|
26
|
+
medium: { caveman: "lite", rtk: true, ponytail: "lite" },
|
|
27
|
+
balanced: { caveman: "full", rtk: true, ponytail: "full" },
|
|
28
|
+
max: { caveman: "ultra", rtk: true, ponytail: "ultra" },
|
|
29
|
+
};
|
|
22
30
|
function parseEnum(value, valid, flag) {
|
|
23
31
|
if (value === undefined)
|
|
24
32
|
return undefined;
|
|
@@ -84,9 +92,11 @@ Commands:
|
|
|
84
92
|
|
|
85
93
|
Options:
|
|
86
94
|
--scope user|project|both
|
|
87
|
-
--
|
|
88
|
-
--
|
|
89
|
-
--
|
|
95
|
+
--remove-ponytail (uninstall: also remove the Ponytail plugin)
|
|
96
|
+
--remove-rtk (uninstall: also remove the RTK binary)
|
|
97
|
+
--combo-default off|medium|balanced|max (implies caveman, rtk, ponytail)
|
|
98
|
+
--caveman-default off|lite|full|ultra|wenyan (override; default follows combo)
|
|
99
|
+
--rtk-default on|off (override; default follows combo)
|
|
90
100
|
--yes, -y
|
|
91
101
|
--dry-run
|
|
92
102
|
--verbose
|
|
@@ -165,8 +175,8 @@ async function ensureExtensionInConfig(configPath, extensionPath, label, options
|
|
|
165
175
|
console.log(` [dry-run] would add ${label} to config.yml: ${normalizedPath}`);
|
|
166
176
|
return true;
|
|
167
177
|
}
|
|
168
|
-
//
|
|
169
|
-
const emptyArrayIdx = lines.findIndex((l) => /^\s*extensions\s*:\s
|
|
178
|
+
// ponytail: omp ships "extensions: null"; appending list items under a null scalar breaks YAML parsing. Normalize null/~/[]/empty to a mapping key first.
|
|
179
|
+
const emptyArrayIdx = lines.findIndex((l) => /^\s*extensions\s*:\s*(?:\[\s*\]|null|~)?\s*$/i.test(l));
|
|
170
180
|
if (emptyArrayIdx !== -1) {
|
|
171
181
|
lines[emptyArrayIdx] = "extensions:";
|
|
172
182
|
lines.splice(emptyArrayIdx + 1, 0, line, "");
|
|
@@ -210,6 +220,8 @@ async function ensureExtensionAfterConfigEntry(configPath, extensionPath, afterP
|
|
|
210
220
|
lines.push("extensions:", line, "");
|
|
211
221
|
}
|
|
212
222
|
else {
|
|
223
|
+
if (/^\s*extensions\s*:\s*(?:\[\s*\]|null|~)?\s*$/i.test(lines[extensionsIndex]))
|
|
224
|
+
lines[extensionsIndex] = "extensions:";
|
|
213
225
|
lines.splice(extensionsIndex + 1, 0, line);
|
|
214
226
|
}
|
|
215
227
|
}
|
|
@@ -790,6 +802,8 @@ async function runUninstall(options = {}) {
|
|
|
790
802
|
const extDir = path.join(HOME, ".omp", "agent", "extensions");
|
|
791
803
|
const configPath = path.join(HOME, ".omp", "agent", "config.yml");
|
|
792
804
|
const rtkBin = path.join(HOME, ".bun", "bin", IS_WINDOWS ? "rtk.exe" : "rtk");
|
|
805
|
+
const pluginsDir = path.join(HOME, ".omp", "plugins");
|
|
806
|
+
const ponytailPkgDir = path.join(pluginsDir, "node_modules", "@dietrichgebert", "ponytail");
|
|
793
807
|
const targets = [
|
|
794
808
|
path.join(extDir, "caveman-session"),
|
|
795
809
|
path.join(extDir, "rtk-session"),
|
|
@@ -797,6 +811,8 @@ async function runUninstall(options = {}) {
|
|
|
797
811
|
path.join(extDir, "combo-toggle"),
|
|
798
812
|
path.join(extDir, "shared"),
|
|
799
813
|
path.join(extDir, "amanai-reward"),
|
|
814
|
+
// Only consumed by ai-addons-updater (removed above); otherwise orphaned.
|
|
815
|
+
path.join(extDir, "lib"),
|
|
800
816
|
// Legacy always-on combo helper; imports shared/session-state.js, so it
|
|
801
817
|
// breaks with a module-not-found warning once the shared dir is removed.
|
|
802
818
|
path.join(extDir, "aaa-combo-boot"),
|
|
@@ -805,6 +821,9 @@ async function runUninstall(options = {}) {
|
|
|
805
821
|
for (const t of targets) {
|
|
806
822
|
console.log(` ${t}`);
|
|
807
823
|
}
|
|
824
|
+
if (shouldRemovePonytail) {
|
|
825
|
+
console.log(` ${ponytailPkgDir} (ponytail plugin package)`);
|
|
826
|
+
}
|
|
808
827
|
if (shouldRemoveRtk) {
|
|
809
828
|
console.log(` ${rtkBin}`);
|
|
810
829
|
}
|
|
@@ -851,8 +870,62 @@ async function runUninstall(options = {}) {
|
|
|
851
870
|
}
|
|
852
871
|
}
|
|
853
872
|
}
|
|
873
|
+
// Remove the Ponytail plugin package the installer added (dep, files,
|
|
874
|
+
// lock entry); the config.yml entry was filtered above.
|
|
875
|
+
if (shouldRemovePonytail) {
|
|
876
|
+
const pluginsPkgPath = path.join(pluginsDir, "package.json");
|
|
877
|
+
const ponytailRaw = await readTextIfExists(pluginsPkgPath);
|
|
878
|
+
if (ponytailRaw) {
|
|
879
|
+
try {
|
|
880
|
+
const pkg = JSON.parse(ponytailRaw);
|
|
881
|
+
if (pkg.dependencies && "@dietrichgebert/ponytail" in pkg.dependencies) {
|
|
882
|
+
if (shouldDryRun)
|
|
883
|
+
console.log(` [dry-run] would remove @dietrichgebert/ponytail from ${pluginsPkgPath}`);
|
|
884
|
+
else {
|
|
885
|
+
delete pkg.dependencies["@dietrichgebert/ponytail"];
|
|
886
|
+
await fs.writeFile(pluginsPkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
887
|
+
console.log(" [write] Removed @dietrichgebert/ponytail from plugins/package.json");
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
catch {
|
|
892
|
+
debug("Could not update plugins/package.json for ponytail");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
try {
|
|
896
|
+
if (shouldDryRun)
|
|
897
|
+
console.log(` [dry-run] would remove ${ponytailPkgDir}`);
|
|
898
|
+
else {
|
|
899
|
+
await fs.rm(ponytailPkgDir, { recursive: true, force: true });
|
|
900
|
+
console.log(` [rm] ${ponytailPkgDir}`);
|
|
901
|
+
await fs.rm(path.dirname(ponytailPkgDir));
|
|
902
|
+
console.log(` [rm] ${path.dirname(ponytailPkgDir)} (empty scope)`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
catch {
|
|
906
|
+
debug("Could not remove ponytail package dir (scope may hold other packages)");
|
|
907
|
+
}
|
|
908
|
+
const lockPath = path.join(pluginsDir, "omp-plugins.lock.json");
|
|
909
|
+
const lockRaw = await readTextIfExists(lockPath);
|
|
910
|
+
if (lockRaw) {
|
|
911
|
+
try {
|
|
912
|
+
const lock = JSON.parse(lockRaw);
|
|
913
|
+
if (lock.plugins && "@dietrichgebert/ponytail" in lock.plugins) {
|
|
914
|
+
if (shouldDryRun)
|
|
915
|
+
console.log(` [dry-run] would remove @dietrichgebert/ponytail from ${lockPath}`);
|
|
916
|
+
else {
|
|
917
|
+
delete lock.plugins["@dietrichgebert/ponytail"];
|
|
918
|
+
await fs.writeFile(lockPath, JSON.stringify(lock, null, 2) + "\n", "utf8");
|
|
919
|
+
console.log(` [write] Removed @dietrichgebert/ponytail from ${lockPath}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
catch {
|
|
924
|
+
debug("Could not update omp-plugins.lock.json for ponytail");
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
854
928
|
// Remove our plugin registration from ~/.omp/plugins
|
|
855
|
-
const pluginsDir = path.join(HOME, ".omp", "plugins");
|
|
856
929
|
const pluginsPkgPath = path.join(pluginsDir, "package.json");
|
|
857
930
|
const pluginsPkgRaw = await readTextIfExists(pluginsPkgPath);
|
|
858
931
|
if (pluginsPkgRaw) {
|
|
@@ -958,6 +1031,7 @@ function defaultProfile() {
|
|
|
958
1031
|
comboDefault: "off",
|
|
959
1032
|
cavemanDefault: "off",
|
|
960
1033
|
rtkDefault: false,
|
|
1034
|
+
ponytailDefault: "off",
|
|
961
1035
|
};
|
|
962
1036
|
}
|
|
963
1037
|
function tty() {
|
|
@@ -965,29 +1039,51 @@ function tty() {
|
|
|
965
1039
|
}
|
|
966
1040
|
async function resolveProfile() {
|
|
967
1041
|
const profile = defaultProfile();
|
|
968
|
-
//
|
|
969
|
-
//
|
|
1042
|
+
// Single interactive prompt: the Combo preset implies all three modes.
|
|
1043
|
+
// Only for a real user at a terminal, only when no default flags were
|
|
1044
|
+
// given, and never for --apply-update runs.
|
|
970
1045
|
if (tty() && !profileFlagsGiven && !applyUpdate && (install || reinstall)) {
|
|
971
1046
|
const comboAnswer = (await ask(" Default Combo preset on session start? [off/medium/balanced/max] (off): ")).trim().toLowerCase();
|
|
972
1047
|
if (comboAnswer && comboAnswer in COMBO_DEFAULTS)
|
|
973
1048
|
profile.comboDefault = comboAnswer;
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
profile.cavemanDefault = cavemanAnswer;
|
|
977
|
-
const rtkAnswer = (await ask(" Default RTK state on session start? [on/off] (off): ")).trim().toLowerCase();
|
|
978
|
-
if (rtkAnswer === "on" || rtkAnswer === "off")
|
|
979
|
-
profile.rtkDefault = rtkAnswer === "on";
|
|
980
|
-
}
|
|
981
|
-
// Explicit flags always win over the prompt.
|
|
1049
|
+
}
|
|
1050
|
+
// Explicit flags always win. Caveman/RTK flags override the Combo preset.
|
|
982
1051
|
if (comboDefaultFlag !== undefined)
|
|
983
1052
|
profile.comboDefault = comboDefaultFlag;
|
|
1053
|
+
const preset = COMBO_PRESET_MODES[profile.comboDefault] ?? COMBO_PRESET_MODES.off;
|
|
1054
|
+
profile.cavemanDefault = preset.caveman;
|
|
1055
|
+
profile.rtkDefault = preset.rtk;
|
|
1056
|
+
profile.ponytailDefault = preset.ponytail;
|
|
984
1057
|
if (cavemanDefaultFlag !== undefined)
|
|
985
1058
|
profile.cavemanDefault = cavemanDefaultFlag;
|
|
986
1059
|
if (rtkDefaultFlag !== undefined)
|
|
987
1060
|
profile.rtkDefault = rtkDefaultFlag === "on";
|
|
988
|
-
console.log(` Profile: combo default=${profile.comboDefault}
|
|
1061
|
+
console.log(` Profile: combo default=${profile.comboDefault} (caveman=${profile.cavemanDefault} · rtk=${profile.rtkDefault ? "on" : "off"} · ponytail=${profile.ponytailDefault})`);
|
|
989
1062
|
return profile;
|
|
990
1063
|
}
|
|
1064
|
+
// ponytail: post-install guard. List entries under `extensions: null` break
|
|
1065
|
+
// OMP launch, so fail loudly here instead of at the next OMP start.
|
|
1066
|
+
async function validateConfigExtensions(agentDir, options) {
|
|
1067
|
+
if (options.dryRun)
|
|
1068
|
+
return;
|
|
1069
|
+
const raw = await readTextIfExists(path.join(agentDir, "config.yml"));
|
|
1070
|
+
if (!raw)
|
|
1071
|
+
return;
|
|
1072
|
+
const lines = raw.split("\n");
|
|
1073
|
+
const keyIdx = lines.findIndex((l) => /^\s*extensions\s*:/i.test(l));
|
|
1074
|
+
if (keyIdx === -1)
|
|
1075
|
+
return;
|
|
1076
|
+
const scalarNull = /^\s*extensions\s*:\s*(null|~|\[\s*\])\s*$/i.test(lines[keyIdx]);
|
|
1077
|
+
const hasEntries = lines.slice(keyIdx + 1).some((l) => /^\s*-\s+\S/.test(l));
|
|
1078
|
+
if (scalarNull && hasEntries) {
|
|
1079
|
+
console.log(" [fail] config.yml lists extensions under `extensions: null` — OMP will fail to launch.");
|
|
1080
|
+
console.log(" [hint] Replace the `extensions: null` line with `extensions:`, then reinstall.");
|
|
1081
|
+
process.exitCode = 1;
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
console.log(" [ok] config.yml extensions key valid");
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
991
1087
|
// Persist the profile as omp plugin settings so `omp plugin config get`
|
|
992
1088
|
// reflects the choice and the extensions pick it up on session start.
|
|
993
1089
|
async function writePluginSettings(profile, options) {
|
|
@@ -1009,6 +1105,7 @@ async function writePluginSettings(profile, options) {
|
|
|
1009
1105
|
settings.comboDefault = profile.comboDefault;
|
|
1010
1106
|
settings.cavemanDefault = profile.cavemanDefault;
|
|
1011
1107
|
settings.rtkDefault = profile.rtkDefault;
|
|
1108
|
+
settings.ponytailDefault = profile.ponytailDefault;
|
|
1012
1109
|
config.settings[PACKAGE_NAME] = settings;
|
|
1013
1110
|
if (options.dryRun) {
|
|
1014
1111
|
console.log(` [dry-run] would write plugin settings (${PACKAGE_NAME}) to ${lockPath}`);
|
|
@@ -1120,6 +1217,7 @@ async function main() {
|
|
|
1120
1217
|
await stepAmanaiReward(userExtDir, options, selfPlugin);
|
|
1121
1218
|
if (selfPlugin)
|
|
1122
1219
|
await writePluginSettings(profile, options);
|
|
1220
|
+
await validateConfigExtensions(userDir, options);
|
|
1123
1221
|
}
|
|
1124
1222
|
if (scope === "2" || scope === "3") {
|
|
1125
1223
|
console.log("\n--- Project-level install ---");
|