@krtclcdy/tersio 2.25.5 → 2.25.7

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 (231) hide show
  1. package/README.md +42 -38
  2. package/dashboard/dist/index.html +15 -15
  3. package/dist/bench/code-out/pfull-0/debounce.js +13 -0
  4. package/dist/bench/code-out/pfull-0/deepClone.js +18 -0
  5. package/dist/bench/code-out/pfull-0/groupBy.js +15 -0
  6. package/dist/bench/code-out/pfull-1/debounce.js +13 -0
  7. package/dist/bench/code-out/pfull-1/deepClone.js +17 -0
  8. package/dist/bench/code-out/pfull-1/groupBy.js +14 -0
  9. package/dist/bench/code-out/pfull-2/debounce.js +13 -0
  10. package/dist/bench/code-out/pfull-2/deepClone.js +18 -0
  11. package/dist/bench/code-out/pfull-2/groupBy.js +15 -0
  12. package/dist/bench/code-out/pfull-3/debounce.js +12 -0
  13. package/dist/bench/code-out/pfull-3/deepClone.js +17 -0
  14. package/dist/bench/code-out/pfull-3/groupBy.js +7 -0
  15. package/dist/bench/code-out/pfull-4/debounce.js +10 -0
  16. package/dist/bench/code-out/pfull-4/deepClone.js +17 -0
  17. package/dist/bench/code-out/pfull-4/groupBy.js +14 -0
  18. package/dist/bench/code-out/plite-0/debounce.js +13 -0
  19. package/dist/bench/code-out/plite-0/deepClone.js +18 -0
  20. package/dist/bench/code-out/plite-0/groupBy.js +15 -0
  21. package/dist/bench/code-out/plite-1/debounce.js +13 -0
  22. package/dist/bench/code-out/plite-1/deepClone.js +17 -0
  23. package/dist/bench/code-out/plite-1/groupBy.js +11 -0
  24. package/dist/bench/code-out/plite-2/debounce.js +12 -0
  25. package/dist/bench/code-out/plite-2/deepClone.js +17 -0
  26. package/dist/bench/code-out/plite-2/groupBy.js +14 -0
  27. package/dist/bench/code-out/plite-3/debounce.js +12 -0
  28. package/dist/bench/code-out/plite-3/deepClone.js +17 -0
  29. package/dist/bench/code-out/plite-3/groupBy.js +14 -0
  30. package/dist/bench/code-out/plite-4/debounce.js +12 -0
  31. package/dist/bench/code-out/plite-4/deepClone.js +17 -0
  32. package/dist/bench/code-out/plite-4/groupBy.js +14 -0
  33. package/dist/bench/code-out/pultra-0/debounce.js +12 -0
  34. package/dist/bench/code-out/pultra-0/deepClone.js +20 -0
  35. package/dist/bench/code-out/pultra-0/groupBy.js +14 -0
  36. package/dist/bench/code-out/pultra-1/debounce.js +10 -0
  37. package/dist/bench/code-out/pultra-1/deepClone.js +17 -0
  38. package/dist/bench/code-out/pultra-1/groupBy.js +7 -0
  39. package/dist/bench/code-out/pultra-2/debounce.js +13 -0
  40. package/dist/bench/code-out/pultra-2/deepClone.js +18 -0
  41. package/dist/bench/code-out/pultra-2/groupBy.js +15 -0
  42. package/dist/bench/code-out/pultra-3/debounce.js +13 -0
  43. package/dist/bench/code-out/pultra-3/deepClone.js +18 -0
  44. package/dist/bench/code-out/pultra-3/groupBy.js +15 -0
  45. package/dist/bench/code-out/pultra-4/debounce.js +13 -0
  46. package/dist/bench/code-out/pultra-4/deepClone.js +18 -0
  47. package/dist/bench/code-out/pultra-4/groupBy.js +15 -0
  48. package/dist/bench/code-out/run-0/debounce.js +12 -0
  49. package/dist/bench/code-out/run-0/deepClone.js +17 -0
  50. package/dist/bench/code-out/run-0/groupBy.js +14 -0
  51. package/dist/bench/code-out/run-1/debounce.js +13 -0
  52. package/dist/bench/code-out/run-1/deepClone.js +15 -0
  53. package/dist/bench/code-out/run-1/groupBy.js +13 -0
  54. package/dist/bench/code-out/run-2/debounce.js +12 -0
  55. package/dist/bench/code-out/run-2/deepClone.js +18 -0
  56. package/dist/bench/code-out/run-2/groupBy.js +13 -0
  57. package/dist/bench/code-out/run-3/debounce.js +12 -0
  58. package/dist/bench/code-out/run-3/deepClone.js +18 -0
  59. package/dist/bench/code-out/run-3/groupBy.js +14 -0
  60. package/dist/bench/code-out/run-4/debounce.js +12 -0
  61. package/dist/bench/code-out/run-4/deepClone.js +16 -0
  62. package/dist/bench/code-out/run-4/groupBy.js +13 -0
  63. package/dist/cli/backups.js +7 -14
  64. package/dist/cli/banner.js +3 -3
  65. package/dist/cli/common.js +29 -13
  66. package/dist/cli/currency.js +1 -1
  67. package/dist/cli/dashboard.js +66 -35
  68. package/dist/cli/doctor-fix.js +204 -19
  69. package/dist/cli/doctor.js +263 -40
  70. package/dist/cli/hosts.js +25 -6
  71. package/dist/cli/install.js +150 -49
  72. package/dist/cli/interactive.js +3 -3
  73. package/dist/cli/manifest.js +109 -9
  74. package/dist/cli/profile.js +13 -8
  75. package/dist/cli/rtk-wiring.js +1 -1
  76. package/dist/cli/settings.js +20 -5
  77. package/dist/cli/uninstall.js +4 -4
  78. package/dist/cli/update.js +6 -7
  79. package/dist/cli/usage.js +6 -9
  80. package/dist/extensions/caveman/index.js +10 -4
  81. package/dist/extensions/caveman/rule-lite.md +77 -0
  82. package/dist/extensions/caveman/rule-megacave-lite.md +59 -0
  83. package/dist/extensions/caveman/rule-megacave-ultra.md +59 -0
  84. package/dist/extensions/caveman/rule-megacave.md +5 -3
  85. package/dist/extensions/caveman/rule-ultra.md +4 -4
  86. package/dist/extensions/caveman/rule.md +55 -45
  87. package/dist/extensions/combo/index.js +85 -25
  88. package/dist/extensions/commands/index.js +1 -1
  89. package/dist/extensions/pstack/index.js +121 -0
  90. package/dist/extensions/pstack/rule.md +141 -0
  91. package/dist/extensions/rtk/filter.js +0 -1
  92. package/dist/extensions/rtk/session.js +20 -12
  93. package/dist/extensions/server.js +90 -6
  94. package/dist/extensions/shared/agent-stats.js +214 -278
  95. package/dist/extensions/shared/brand-marks.js +33 -34
  96. package/dist/extensions/shared/carbon.js +1 -1
  97. package/dist/extensions/shared/plugin-settings.js +11 -6
  98. package/dist/extensions/shared/pricing.js +8 -16
  99. package/dist/extensions/shared/rtk-eligible.js +84 -0
  100. package/dist/extensions/shared/rtk-gain.js +5 -10
  101. package/dist/extensions/shared/session-state.js +15 -10
  102. package/dist/extensions/shared/sqlite.js +162 -0
  103. package/dist/extensions/shared/status.js +8 -9
  104. package/dist/extensions/shared/types.js +1 -1
  105. package/dist/extensions/shared/usage-ledger.js +155 -61
  106. package/dist/extensions/shared/usage-store.js +111 -52
  107. package/dist/extensions/shared/utils.js +5 -5
  108. package/dist/extensions/timing/index.js +31 -0
  109. package/dist/extensions/updater/index.js +3 -6
  110. package/dist/tersio.js +8 -3
  111. package/extensions/caveman/index.ts +10 -4
  112. package/extensions/caveman/rule-lite.md +77 -0
  113. package/extensions/caveman/rule-megacave-lite.md +59 -0
  114. package/extensions/caveman/rule-megacave-ultra.md +59 -0
  115. package/extensions/caveman/rule-megacave.md +5 -3
  116. package/extensions/caveman/rule-ultra.md +4 -4
  117. package/extensions/caveman/rule.md +55 -45
  118. package/extensions/combo/index.ts +86 -23
  119. package/extensions/commands/index.ts +1 -1
  120. package/extensions/pstack/index.ts +130 -0
  121. package/extensions/pstack/playbooks/authoring-a-skill.md +12 -0
  122. package/extensions/pstack/playbooks/autonomous-run.md +13 -0
  123. package/extensions/pstack/playbooks/autopilot-full.md +13 -0
  124. package/extensions/pstack/playbooks/autopilot-stack.md +16 -0
  125. package/extensions/pstack/playbooks/babysit.md +23 -0
  126. package/extensions/pstack/playbooks/bug-fix.md +15 -0
  127. package/extensions/pstack/playbooks/eval.md +25 -0
  128. package/extensions/pstack/playbooks/feature.md +21 -0
  129. package/extensions/pstack/playbooks/hillclimb.md +21 -0
  130. package/extensions/pstack/playbooks/investigation.md +14 -0
  131. package/extensions/pstack/playbooks/multi-phase-plan.md +155 -0
  132. package/extensions/pstack/playbooks/opening-a-pr.md +34 -0
  133. package/extensions/pstack/playbooks/orchestrate.md +111 -0
  134. package/extensions/pstack/playbooks/pause-safely.md +10 -0
  135. package/extensions/pstack/playbooks/perf-issue.md +25 -0
  136. package/extensions/pstack/playbooks/prototype.md +14 -0
  137. package/extensions/pstack/playbooks/refactoring.md +16 -0
  138. package/extensions/pstack/playbooks/runtime-forensics.md +11 -0
  139. package/extensions/pstack/playbooks/session-pickup.md +11 -0
  140. package/extensions/pstack/playbooks/shipping.md +17 -0
  141. package/extensions/pstack/playbooks/trace-forensics.md +14 -0
  142. package/extensions/pstack/playbooks/visual-parity.md +11 -0
  143. package/extensions/pstack/playbooks/worktree-cleanup.md +12 -0
  144. package/extensions/pstack/principles/attack-the-premise.md +22 -0
  145. package/extensions/pstack/principles/boundary-discipline.md +33 -0
  146. package/extensions/pstack/principles/build-the-lever.md +22 -0
  147. package/extensions/pstack/principles/encode-lessons-in-structure.md +10 -0
  148. package/extensions/pstack/principles/exhaust-the-design-space.md +8 -0
  149. package/extensions/pstack/principles/experience-first.md +18 -0
  150. package/extensions/pstack/principles/explain-the-number.md +16 -0
  151. package/extensions/pstack/principles/fix-root-causes.md +23 -0
  152. package/extensions/pstack/principles/foundational-thinking.md +20 -0
  153. package/extensions/pstack/principles/guard-the-context-window.md +11 -0
  154. package/extensions/pstack/principles/laziness-protocol.md +9 -0
  155. package/extensions/pstack/principles/make-operations-idempotent.md +23 -0
  156. package/extensions/pstack/principles/migrate-callers-then-delete-legacy-apis.md +21 -0
  157. package/extensions/pstack/principles/minimize-reader-load.md +17 -0
  158. package/extensions/pstack/principles/model-the-domain.md +23 -0
  159. package/extensions/pstack/principles/never-block-on-the-human.md +14 -0
  160. package/extensions/pstack/principles/outcome-oriented-execution.md +20 -0
  161. package/extensions/pstack/principles/prove-it-works.md +21 -0
  162. package/extensions/pstack/principles/redesign-from-first-principles.md +15 -0
  163. package/extensions/pstack/principles/separate-before-serializing-shared-state.md +15 -0
  164. package/extensions/pstack/principles/sequence-verifiable-units.md +16 -0
  165. package/extensions/pstack/principles/subtract-before-you-add.md +17 -0
  166. package/extensions/pstack/principles/test-behavior-not-implementation.md +20 -0
  167. package/extensions/pstack/principles/type-system-discipline.md +17 -0
  168. package/extensions/pstack/references/bugbot-triage.md +142 -0
  169. package/extensions/pstack/rule.md +141 -0
  170. package/extensions/pstack/skills/architect/SKILL.md +78 -0
  171. package/extensions/pstack/skills/architect/references/design-red-flags.md +57 -0
  172. package/extensions/pstack/skills/architect/references/rationale-template.md +35 -0
  173. package/extensions/pstack/skills/architect/references/runner-prompt.md +20 -0
  174. package/extensions/pstack/skills/arena/SKILL.md +47 -0
  175. package/extensions/pstack/skills/benchmark-checklist/SKILL.md +38 -0
  176. package/extensions/pstack/skills/blast-radius/SKILL.md +49 -0
  177. package/extensions/pstack/skills/bro/SKILL.md +6 -0
  178. package/extensions/pstack/skills/correct/SKILL.md +31 -0
  179. package/extensions/pstack/skills/figure-it-out/SKILL.md +51 -0
  180. package/extensions/pstack/skills/how/SKILL.md +35 -0
  181. package/extensions/pstack/skills/how/references/explainer-prompt.md +55 -0
  182. package/extensions/pstack/skills/how/references/explorer-prompt.md +35 -0
  183. package/extensions/pstack/skills/interrogate/SKILL.md +73 -0
  184. package/extensions/pstack/skills/interrogate/references/code-quality-review.md +47 -0
  185. package/extensions/pstack/skills/interrogate/references/lead-judgment.md +58 -0
  186. package/extensions/pstack/skills/interrogate/references/reviewer-prompt.md +62 -0
  187. package/extensions/pstack/skills/interrogate/references/rubric.md +77 -0
  188. package/extensions/pstack/skills/no-comments/SKILL.md +23 -0
  189. package/extensions/pstack/skills/reflect/SKILL.md +66 -0
  190. package/extensions/pstack/skills/reflect/references/divergent-reviewer.md +38 -0
  191. package/extensions/pstack/skills/reflect/references/judgment-reviewer.md +37 -0
  192. package/extensions/pstack/skills/reflect/references/synthesizer.md +56 -0
  193. package/extensions/pstack/skills/reflect/references/tooling-reviewer.md +48 -0
  194. package/extensions/pstack/skills/show-me-your-work/SKILL.md +81 -0
  195. package/extensions/pstack/skills/swarm/SKILL.md +45 -0
  196. package/extensions/pstack/skills/tdd/SKILL.md +41 -0
  197. package/extensions/pstack/skills/technical-writing/SKILL.md +105 -0
  198. package/extensions/pstack/skills/unslop/SKILL.md +61 -0
  199. package/extensions/pstack/skills/why/SKILL.md +97 -0
  200. package/extensions/pstack/skills/why/references/epistemics.md +71 -0
  201. package/extensions/pstack/skills/why/references/investigator-prompt.md +84 -0
  202. package/extensions/pstack/skills/why/references/source-playbook.md +17 -0
  203. package/extensions/pstack/skills/why/references/sources/code-archaeology.md +51 -0
  204. package/extensions/pstack/skills/why/references/sources/databricks.md +70 -0
  205. package/extensions/pstack/skills/why/references/sources/datadog.md +97 -0
  206. package/extensions/pstack/skills/why/references/sources/incident-postmortem.md +5 -0
  207. package/extensions/pstack/skills/why/references/sources/linear.md +48 -0
  208. package/extensions/pstack/skills/why/references/sources/notion.md +55 -0
  209. package/extensions/pstack/skills/why/references/sources/sentry.md +66 -0
  210. package/extensions/pstack/skills/why/references/sources/slack.md +17 -0
  211. package/extensions/pstack/skills/why/references/synthesizer-prompt.md +129 -0
  212. package/extensions/rtk/filter.ts +0 -1
  213. package/extensions/rtk/session.ts +19 -11
  214. package/extensions/server.ts +72 -7
  215. package/extensions/shared/agent-stats.ts +226 -278
  216. package/extensions/shared/brand-marks.ts +34 -34
  217. package/extensions/shared/carbon.ts +1 -1
  218. package/extensions/shared/plugin-settings.ts +12 -6
  219. package/extensions/shared/pricing.ts +10 -26
  220. package/extensions/shared/rtk-eligible.ts +83 -0
  221. package/extensions/shared/rtk-gain.ts +5 -10
  222. package/extensions/shared/session-state.ts +18 -13
  223. package/extensions/shared/sqlite.ts +162 -0
  224. package/extensions/shared/status.ts +9 -9
  225. package/extensions/shared/types.ts +2 -1
  226. package/extensions/shared/usage-ledger.ts +157 -66
  227. package/extensions/shared/usage-store.ts +120 -52
  228. package/extensions/shared/utils.ts +5 -5
  229. package/extensions/timing/index.ts +44 -0
  230. package/extensions/updater/index.ts +3 -8
  231. package/package.json +21 -9
@@ -1,7 +1,7 @@
1
1
  // cli/profile.ts — session-start defaults and the display-currency default,
2
2
  import { existsSync, promises as fs, readFileSync } from 'node:fs';
3
3
  import path from 'node:path';
4
- import { CAVEMAN_DEFAULTS, COMBO_PRESET_MODES, PACKAGE_NAME, PONYTAIL_DEFAULTS, verbose, } from './common.js';
4
+ import { CAVEMAN_DEFAULTS, COMBO_PRESET_MODES, PACKAGE_NAME, PONYTAIL_DEFAULTS, PSTACK_DEFAULTS, verbose, } from './common.js';
5
5
  import os from 'node:os';
6
6
  import { DEFAULT_CURRENCY, isCurrencyCode } from './currency.js';
7
7
  import { readTextIfExists } from '../extensions/shared/utils.js';
@@ -21,12 +21,13 @@ function defaultProfile() {
21
21
  cavemanDefault: 'off',
22
22
  rtkDefault: false,
23
23
  ponytailDefault: 'off',
24
+ pstackDefault: 'off',
24
25
  currency: DEFAULT_CURRENCY,
25
26
  backupSchedule: 'monthly',
26
27
  subagentMarkers: [],
27
28
  };
28
29
  }
29
- // Seed once from OMP plugin settings so a pre-~/.tersio install keeps its values. Sync: awaiting let piped stdin arrive before `ask()` attached, so a scripted answer was swallowed and a destructive confirm defaulted to abort.
30
+ // Seed from OMP settings so pre-~/.tersio installs keep values. Sync: awaiting let piped stdin beat `ask()`.
30
31
  function storedProfileSync() {
31
32
  const base = defaultProfile();
32
33
  const stored = parseStored(readTextIfExistsSync(tersioSettingsFile()) ?? readTextIfExistsSync(legacyOmpLockPath()));
@@ -44,6 +45,8 @@ function applyStored(base, stored) {
44
45
  base.rtkDefault = stored.rtkDefault;
45
46
  if (typeof stored.ponytailDefault === 'string' && PONYTAIL_DEFAULTS.has(stored.ponytailDefault))
46
47
  base.ponytailDefault = stored.ponytailDefault;
48
+ if (typeof stored.pstackDefault === 'string' && PSTACK_DEFAULTS.has(stored.pstackDefault))
49
+ base.pstackDefault = stored.pstackDefault;
47
50
  if (typeof stored.currency === 'string' && isCurrencyCode(stored.currency.trim().toUpperCase())) {
48
51
  base.currency = stored.currency.trim().toUpperCase();
49
52
  }
@@ -80,7 +83,7 @@ function parseStored(raw) {
80
83
  return null;
81
84
  }
82
85
  }
83
- // Persist the profile where every host reads it. `omp plugin config get` no longer reports it; `tersio settings` does.
86
+ // Persist profile where every host reads it. `omp plugin config get` no longer reports it; `tersio settings` does.
84
87
  async function writePluginSettings(profile, options) {
85
88
  const file = tersioSettingsFile();
86
89
  const values = {
@@ -90,6 +93,7 @@ async function writePluginSettings(profile, options) {
90
93
  cavemanDefault: profile.cavemanDefault,
91
94
  rtkDefault: profile.rtkDefault,
92
95
  ponytailDefault: profile.ponytailDefault,
96
+ pstackDefault: profile.pstackDefault,
93
97
  currency: profile.currency,
94
98
  backupSchedule: profile.backupSchedule,
95
99
  ...(profile.subagentMarkers.length > 0 ? { subagentMarkers: profile.subagentMarkers } : {}),
@@ -104,21 +108,22 @@ async function writePluginSettings(profile, options) {
104
108
  console.log(` [write] Session defaults in ${file}`);
105
109
  }
106
110
  function formatProfile(profile) {
107
- return `combo=${profile.comboDefault} (caveman=${profile.cavemanDefault} · rtk=${profile.rtkDefault ? 'on' : 'off'} · ponytail=${profile.ponytailDefault}) · currency=${profile.currency}`;
111
+ return `combo=${profile.comboDefault} (caveman=${profile.cavemanDefault} · rtk=${profile.rtkDefault ? 'on' : 'off'} · ponytail=${profile.ponytailDefault} · pstack=${profile.pstackDefault}) · currency=${profile.currency}`;
108
112
  }
109
113
  export { defaultProfile, formatProfile, storedProfile, storedProfileSync, writePluginSettings };
110
114
  /** The status line the extensions print, read from the persisted profile. */
111
115
  export function formatCliStatus(profile) {
112
- const { comboDefault, cavemanDefault, rtkDefault, ponytailDefault } = profile;
113
- if (comboDefault === 'off' && cavemanDefault === 'off' && !rtkDefault && ponytailDefault === 'off') {
116
+ const { comboDefault, cavemanDefault, rtkDefault, ponytailDefault, pstackDefault } = profile;
117
+ if (comboDefault === 'off' && cavemanDefault === 'off' && !rtkDefault && ponytailDefault === 'off' && pstackDefault === 'off') {
114
118
  return '🧩 combo OFF';
115
119
  }
116
120
  const preset = COMBO_PRESET_MODES[comboDefault];
117
121
  const isPreset = preset !== undefined
118
122
  && preset.caveman === cavemanDefault
119
123
  && preset.rtk === rtkDefault
120
- && preset.ponytail === ponytailDefault;
124
+ && preset.ponytail === ponytailDefault
125
+ && preset.pstack === pstackDefault;
121
126
  const level = isPreset ? comboDefault.toUpperCase() : 'CUSTOM';
122
127
  const rtk = rtkDefault ? 'ON' : 'OFF';
123
- return `🧩 combo ${level}: 🪨caveman=${cavemanDefault.toUpperCase()} ⚡rtk=${rtk} 🦥ponytail=${ponytailDefault.toUpperCase()}`;
128
+ return `🧩 combo ${level}: 🪨caveman=${cavemanDefault.toUpperCase()} ⚡rtk=${rtk} 🦥ponytail=${ponytailDefault.toUpperCase()} 🥔pstack=${pstackDefault.toUpperCase()}`;
124
129
  }
@@ -61,7 +61,7 @@ function rtkExtensionPath() {
61
61
  const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
62
62
  return path.join(home, '.omp', 'agent', 'extensions', 'rtk.ts');
63
63
  }
64
- // Append rtk.ts after the existing entries (or create the key) so the wire takes effect on the next OMP start.
64
+ // Append rtk.ts so the wire takes effect on the next OMP start.
65
65
  export async function ensureRtkInConfig(options) {
66
66
  const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
67
67
  const configPath = path.join(home, '.omp', 'agent', 'config.yml');
@@ -1,5 +1,5 @@
1
1
  // cli/settings.ts — view/edit session-start defaults and the display currency.
2
- import { CAVEMAN_DEFAULTS, COMBO_DEFAULTS, COMBO_PRESET_MODES, PONYTAIL_DEFAULTS, cavemanDefaultFlag, comboDefaultFlag, currency, currencyGiven, diagScheduleFlag, dryRun, ponytailDefaultFlag, profileFlagsGiven, rtkDefaultFlag, settingArg, subagentMarkerFlags, subagentMarkersGiven, } from './common.js';
2
+ import { CAVEMAN_DEFAULTS, COMBO_DEFAULTS, COMBO_PRESET_MODES, PONYTAIL_DEFAULTS, PSTACK_DEFAULTS, cavemanDefaultFlag, comboDefaultFlag, currency, currencyGiven, diagScheduleFlag, dryRun, ponytailDefaultFlag, pstackDefaultFlag, profileFlagsGiven, rtkDefaultFlag, settingArg, subagentMarkerFlags, subagentMarkersGiven, } from './common.js';
3
3
  import { tersioSettingsFile } from '../extensions/shared/plugin-settings.js';
4
4
  import { CURRENCY_CODES } from './currency.js';
5
5
  import { textTable } from './usage.js';
@@ -14,12 +14,15 @@ function applyFlags(base) {
14
14
  next.cavemanDefault = preset.caveman;
15
15
  next.rtkDefault = preset.rtk;
16
16
  next.ponytailDefault = preset.ponytail;
17
+ next.pstackDefault = preset.pstack;
17
18
  if (cavemanDefaultFlag !== undefined)
18
19
  next.cavemanDefault = cavemanDefaultFlag;
19
20
  if (rtkDefaultFlag !== undefined)
20
21
  next.rtkDefault = rtkDefaultFlag === 'on';
21
22
  if (ponytailDefaultFlag !== undefined)
22
23
  next.ponytailDefault = ponytailDefaultFlag;
24
+ if (pstackDefaultFlag !== undefined)
25
+ next.pstackDefault = pstackDefaultFlag;
23
26
  if (subagentMarkersGiven)
24
27
  next.subagentMarkers = subagentMarkerFlags;
25
28
  if (currencyGiven)
@@ -41,6 +44,7 @@ async function askProfile(current) {
41
44
  cavemanDefault: preset.caveman,
42
45
  rtkDefault: preset.rtk,
43
46
  ponytailDefault: preset.ponytail,
47
+ pstackDefault: preset.pstack,
44
48
  currency: current.currency,
45
49
  backupSchedule: current.backupSchedule,
46
50
  subagentMarkers: current.subagentMarkers,
@@ -82,11 +86,11 @@ async function askDiagSchedule(current) {
82
86
  return null;
83
87
  return picked.value;
84
88
  }
85
- const SETTING_NAMES = ['combo', 'caveman', 'rtk', 'ponytail', 'currency', 'diagnosis', 'markers'];
89
+ const SETTING_NAMES = ['combo', 'caveman', 'rtk', 'ponytail', 'pstack', 'currency', 'diagnosis', 'markers'];
86
90
  function settingsUsage() {
87
- console.log(' Usage: tersio settings [combo|caveman|rtk|ponytail|currency|diagnosis|markers] [--combo-default off|medium|balanced|max] [--caveman-default off|lite|full|ultra|megacave-lite|megacave-full|megacave-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] [--subagent-marker <text>]... [--dry-run]');
91
+ console.log(' Usage: tersio settings [combo|caveman|rtk|ponytail|pstack|currency|diagnosis|markers] [--combo-default off|medium|balanced|max] [--caveman-default off|lite|full|ultra|megacave-lite|megacave-full|megacave-ultra] [--rtk-default on|off] [--ponytail-default off|lite|full|ultra] [--pstack-default on|off] [--currency USD|PHP|EUR|GBP|JPY|KRW|SGD|AUD|CAD|INR] [--diag-schedule manual|daily|weekly|monthly] [--subagent-marker <text>]... [--dry-run]');
88
92
  }
89
- // Single-setting jump: `tersio settings diagnosis` prompts only that value instead of walking the whole chain. Returns false when aborted.
93
+ // Single-setting jump: prompts only that value instead of walking the whole chain; null when aborted.
90
94
  async function runSingleSetting(name, current, nextDiag) {
91
95
  const next = { ...current };
92
96
  let diag = nextDiag;
@@ -105,6 +109,7 @@ async function runSingleSetting(name, current, nextDiag) {
105
109
  next.cavemanDefault = preset.caveman;
106
110
  next.rtkDefault = preset.rtk;
107
111
  next.ponytailDefault = preset.ponytail;
112
+ next.pstackDefault = preset.pstack;
108
113
  break;
109
114
  }
110
115
  case 'caveman': {
@@ -135,6 +140,15 @@ async function runSingleSetting(name, current, nextDiag) {
135
140
  next.ponytailDefault = picked.value;
136
141
  break;
137
142
  }
143
+ case 'pstack': {
144
+ const picked = await askInteractiveChoice('pstack default (rigor mode)', [...PSTACK_DEFAULTS].map((v) => ({
145
+ value: v, label: v,
146
+ })), next.pstackDefault);
147
+ if (picked.status !== 'selected')
148
+ return null;
149
+ next.pstackDefault = picked.value;
150
+ break;
151
+ }
138
152
  case 'currency': {
139
153
  const picked = await askInteractiveChoice('Display currency (usage/dashboard reports)', CURRENCY_CODES.map((v) => ({
140
154
  value: v, label: v,
@@ -173,6 +187,7 @@ function printSettingsTable(current) {
173
187
  ['caveman', current.cavemanDefault, [...CAVEMAN_DEFAULTS].join(' | ')],
174
188
  ['rtk', current.rtkDefault ? 'on' : 'off', 'on | off'],
175
189
  ['ponytail', current.ponytailDefault, [...PONYTAIL_DEFAULTS].join(' | ')],
190
+ ['pstack', current.pstackDefault, [...PSTACK_DEFAULTS].join(' | ')],
176
191
  ['diagnosis', readDiagSchedule(), 'manual | daily | weekly | monthly'],
177
192
  ['markers', current.subagentMarkers.length === 0 ? 'default' : current.subagentMarkers.join(' | '), 'host subagent prompt text'],
178
193
  ];
@@ -180,7 +195,7 @@ function printSettingsTable(current) {
180
195
  console.log(l);
181
196
  }
182
197
  console.log(` Stored: ${tersioSettingsFile()}`);
183
- console.log(` Combo ${current.comboDefault} sets caveman/rtk/ponytail. Tune one: tersio settings <name>`);
198
+ console.log(` Combo ${current.comboDefault} sets all four modes. Tune one: tersio settings <name>`);
184
199
  }
185
200
  async function runSettings() {
186
201
  const current = await storedProfile();
@@ -11,6 +11,7 @@ const PONYTAIL_PKG = '@dietrichgebert/ponytail';
11
11
  const PI_TREE_DIRS = [
12
12
  // What an install writes now.
13
13
  'caveman',
14
+ 'pstack',
14
15
  'rtk',
15
16
  'updater',
16
17
  'combo',
@@ -100,7 +101,7 @@ async function removePiLayer(host, shouldDryRun, shouldRemovePonytail, shouldRem
100
101
  await removeCopiedPonytailSkills(shouldDryRun);
101
102
  }
102
103
  await Promise.all(targets.map((t) => removeUninstallTarget(t, shouldDryRun)));
103
- // rtk's wiring is a loose file, not one of the tree dirs, so it survived --remove-rtk on pi while OMP removed its copy.
104
+ // rtk's wiring is a loose file, not a tree dir, so it survived --remove-rtk on pi while OMP removed its copy.
104
105
  if (shouldRemoveRtk) {
105
106
  await removeUninstallTarget(rtkWiring, shouldDryRun, false);
106
107
  await removeUninstallTarget(path.join(BUN_BIN_DIR, RTK_BINARY_NAME), shouldDryRun, false);
@@ -281,7 +282,6 @@ async function runUninstall(options = {}) {
281
282
  return false;
282
283
  // Remove extension directories (independent paths, so concurrently).
283
284
  await Promise.all(targets.map((t) => removeUninstallTarget(t, shouldDryRun)));
284
- // Remove Combo, mode-reinforcement, and rtk registrations; Ponytail on request.
285
285
  const configRaw = await readTextIfExists(configPath);
286
286
  if (configRaw) {
287
287
  let lines = configRaw.split('\n');
@@ -291,7 +291,7 @@ async function runUninstall(options = {}) {
291
291
  return false;
292
292
  if (shouldRemovePonytail && l.includes('ponytail') && l.includes('pi-extension'))
293
293
  return false;
294
- // Our rtk wiring, absolute or relative. Leaving it listed would keep OMP loading a hook for a package that is no longer installed.
294
+ // Our rtk wiring, absolute or relative. Leaving it listed would keep OMP loading a hook for an uninstalled package.
295
295
  const entry = l.trim().replace(/^-\s*/, '').replace(/^['"]|['"]$/g, '');
296
296
  if (entry.endsWith(`extensions${path.sep}rtk.ts`) || entry.endsWith('extensions/rtk.ts'))
297
297
  return false;
@@ -306,7 +306,7 @@ async function runUninstall(options = {}) {
306
306
  }
307
307
  // Cleared last: writeConfigLines above would just make a fresh one.
308
308
  const cavemanDir = path.join(pluginsDir, 'node_modules', PACKAGE_NAME, 'extensions', 'caveman-session');
309
- for (const backup of [`${configPath}.bak`, path.join(cavemanDir, 'rule.md.bak'), path.join(cavemanDir, 'rule-ultra.md.bak'), path.join(cavemanDir, 'rule-megacave.md.bak')]) {
309
+ for (const backup of [`${configPath}.bak`, path.join(cavemanDir, 'rule.md.bak'), path.join(cavemanDir, 'rule-lite.md.bak'), path.join(cavemanDir, 'rule-megacave-lite.md.bak'), path.join(cavemanDir, 'rule-megacave-ultra.md.bak'), path.join(cavemanDir, 'rule-ultra.md.bak'), path.join(cavemanDir, 'rule-megacave.md.bak')]) {
310
310
  await removeUninstallTarget(backup, shouldDryRun, false);
311
311
  }
312
312
  // Remove the bundled Ponytail copy; its config.yml entry is already filtered.
@@ -35,7 +35,7 @@ async function latestPublishedVersion() {
35
35
  return null;
36
36
  }
37
37
  }
38
- // A newer published version, null when up to date, 'unknown' when the registry is unreachable. Cached for a TTL unless force, which must not trust a cache.
38
+ // A newer version, null when up to date, 'unknown' when the registry is unreachable. Cached for a TTL unless force.
39
39
  async function checkForUpdate(force = false) {
40
40
  const cachePath = tersioDataPath('update-check.json', 'tersio-update-check.json');
41
41
  const cached = parseJsonObject(await readTextIfExists(cachePath));
@@ -48,7 +48,7 @@ async function checkForUpdate(force = false) {
48
48
  await fs.writeFile(cachePath, JSON.stringify({ latest, lastCheck: Date.now() }) + '\n', 'utf8').catch(() => { });
49
49
  return newerThan(latest, PACKAGE_VERSION) ? latest : null;
50
50
  }
51
- // Unreachable registry: a stale cache naming a newer release is still actionable, else report unknown so nobody claims "latest".
51
+ // Unreachable registry: a stale cache naming a newer release is actionable, else unknown, so none claim "latest".
52
52
  return cached?.latest && newerThan(cached.latest, PACKAGE_VERSION) ? cached.latest : 'unknown';
53
53
  }
54
54
  // Race a probe against a timeout; failures resolve null so nothing blocks.
@@ -74,7 +74,7 @@ async function execInherit(cmd, args) {
74
74
  if (code !== 0)
75
75
  throw new Error(`${cmd} exited with code ${code}`);
76
76
  }
77
- // Current → latest per add-on. Every probe is capped and nullable, and the plan prints `unknown` for anything unreachable.
77
+ // Current → latest per add-on. Probes are capped and nullable; the plan prints `unknown` for anything unreachable.
78
78
  async function probeUpdatePlan(cliLatest) {
79
79
  const rtkBin = resolveRtkBinary();
80
80
  const ponytailPkg = path.join(OMP_PLUGINS_DIR, 'node_modules', '@dietrichgebert', 'ponytail', 'package.json');
@@ -98,7 +98,7 @@ async function probeUpdatePlan(cliLatest) {
98
98
  ponytail: ponytailLocalText ? parseJsonObject(ponytailLocalText)?.version ?? null : null,
99
99
  };
100
100
  }
101
- // Every add-on prints a version jump when stale, "up to date" otherwise, and "unknown" when its source cannot be reached.
101
+ // Every add-on prints a version jump when stale, "up to date" otherwise, and "unknown" when unreachable.
102
102
  function planLines(plan) {
103
103
  const stale = [];
104
104
  const status = [];
@@ -147,7 +147,6 @@ async function runLatestUpdate() {
147
147
  // `--prefer-online` beats the local cache, so a stale @latest cannot pin down.
148
148
  const cliLatest = await latestPublishedVersion();
149
149
  const target = cliLatest && /^\d+\.\d+\.\d+$/.test(cliLatest) ? `@${cliLatest}` : '@latest';
150
- // Best-effort: unreachable probes print as unknown.
151
150
  const plan = await probeUpdatePlan(cliLatest);
152
151
  const { stale, status } = planLines(plan);
153
152
  if (dryRun) {
@@ -181,7 +180,7 @@ async function runLatestUpdate() {
181
180
  process.exitCode = 1;
182
181
  return;
183
182
  }
184
- // The npx delegation below only refreshes the OMP-side files; the globally installed CLI keeps its old version until npm -g runs. Refresh both.
183
+ // The npx delegation below only refreshes the OMP-side files; the global CLI keeps its old version until npm -g runs.
185
184
  const globalArgs = IS_WINDOWS
186
185
  ? ['/d', '/s', '/c', 'npm', 'install', '-g', `${PACKAGE_NAME}${target}`, '--no-audit', '--no-fund', '--prefer-online']
187
186
  : ['install', '-g', `${PACKAGE_NAME}${target}`, '--no-audit', '--no-fund', '--prefer-online'];
@@ -211,7 +210,7 @@ async function runLatestUpdate() {
211
210
  ...forwardedArgs,
212
211
  ];
213
212
  const npmCommandArgs = IS_WINDOWS ? ['/d', '/s', '/c', 'npm', ...npmArgs] : npmArgs;
214
- // Inherited stdio, no outer spinner; the delegated installer runs quiet and this parent owns both the plan line and the closing summary.
213
+ // Inherited stdio, no outer spinner; the quiet installer runs, so this parent owns the plan line and closing summary.
215
214
  try {
216
215
  await execInherit(npmCommand, npmCommandArgs);
217
216
  console.log(`Done — tersio ${plan.cli ?? PACKAGE_VERSION} and add-ons updated.`);
package/dist/cli/usage.js CHANGED
@@ -6,7 +6,7 @@ import { readUsageDb, reparseGuardReport, syncUsageDb, usageDbPath } from '../ex
6
6
  import { withInteractiveSpinner } from './interactive.js';
7
7
  import { PACKAGE_VERSION, currency } from './common.js';
8
8
  import { formatCurrency } from './currency.js';
9
- // RTK's history is machine-wide; rows group by command alone. 2000 groups covers a long history while still bounding /data.json.
9
+ // RTK history is machine-wide; rows group by command. 2000 groups covers a long history while bounding /data.json.
10
10
  const RTK_COMMAND_ROWS = 2000;
11
11
  export function summarizeUsage(rows) {
12
12
  refreshPricesIfStale();
@@ -17,7 +17,7 @@ export function summarizeUsage(rows) {
17
17
  detailCounts[r.detail] = (detailCounts[r.detail] ?? 0) + 1;
18
18
  }
19
19
  const byDetail = Object.entries(detailCounts).sort((a, b) => b[1] - a[1]).slice(0, 10);
20
- // usage.db is a cache of the same per-message rows: sync best-effort, read stored, fall back to the live parse when the store is missing or stale.
20
+ // usage.db caches the same per-message rows: sync best-effort, read stored, fall back to the live parse when stale.
21
21
  let synced = false;
22
22
  try {
23
23
  synced = syncUsageDb();
@@ -62,8 +62,7 @@ export function summarizeUsage(rows) {
62
62
  const weakModels = [];
63
63
  const measuredModels = [];
64
64
  for (const [model, t] of Object.entries(session.byModel)) {
65
- // A model is measured only when the host priced every one of its messages; a partly measured
66
- // model would read its unpriced messages as zero, which is the one error worse than a guess.
65
+ // A model counts as measured only when the host priced every message, or unpriced ones would read as zero.
67
66
  const covered = (session.byModelCostMessages[model] ?? 0) >= (session.byModelMessages[model] ?? 0);
68
67
  const measured = covered ? session.byModelMeasured[model] : undefined;
69
68
  const c = usdCost(t, model, measured);
@@ -71,8 +70,7 @@ export function summarizeUsage(rows) {
71
70
  priceTiers[c.tier] = (priceTiers[c.tier] ?? 0) + 1;
72
71
  if (c.tier === 'measured')
73
72
  measuredModels.push(model);
74
- // A tier that is not firm is an estimate, so it is kept out of the firm total rather than
75
- // summed beside a measured cost that would make the whole figure read as a bill.
73
+ // A non-firm tier is kept out of the firm total, or a guessed cost would make the figure read as a bill.
76
74
  if (!PRICE_TIERS_FIRM.includes(c.tier)) {
77
75
  estimatedUsd += c.usd;
78
76
  weakModels.push(model);
@@ -180,7 +178,7 @@ const ROW_CAP = 15;
180
178
  function pad(s, n) {
181
179
  return s.length >= n ? s : s + ' '.repeat(n - s.length);
182
180
  }
183
- // Box-drawing table, plain text (piped-safe, byte-stable). Numeric columns right-align; long cells truncate with an ellipsis. Shared with cli/settings.ts.
181
+ // Box-drawing table, plain text (piped-safe, byte-stable). Numbers right-align; long cells truncate with an ellipsis.
184
182
  function textTable(headers, rows, right = [], maxW = 32) {
185
183
  const cells = [headers, ...rows].map((r) => r.map((c) => (c.length > maxW ? c.slice(0, maxW - 1) + '…' : c)));
186
184
  const widths = headers.map((_, i) => Math.max(...cells.map((r) => r[i].length)));
@@ -203,8 +201,7 @@ function printReport(report) {
203
201
  // A tier that is not firm is named, so a figure that is partly a guess never reads as a bill.
204
202
  const weak = ['tail', 'default'].reduce((sum, tier) => sum + (report.priceTiers[tier] ?? 0), 0);
205
203
  const overridden = report.priceTiers.override ?? 0;
206
- // The count stays in the cell; the names go on their own line below, because the cell is a
207
- // fixed 118 columns and a list of model ids would be truncated to nothing.
204
+ // The count stays in the cell; names go below, since a 118-column cell would truncate a model-id list.
208
205
  const listed = report.weakModels.map((m) => displayModelId(m));
209
206
  const measuredCount = report.measuredModels.length;
210
207
  const costNote = weak > 0
@@ -3,11 +3,15 @@ import { fileURLToPath } from 'node:url';
3
3
  import { getSharedComboState, hasModeState, isOmpSubagentPrompt, lastCustomValue, normalizeInputCommand, normalizeMode, reconcileSharedComboEntries, sessionEntries, setSharedComboListener, setSharedComboMode, systemPromptIncludes } from '../shared/session-state.js';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { injectPromptText, onHostEvent, setExtensionLabel } from '../shared/host.js';
6
- import { announceStatus } from '../shared/status.js';
6
+ import { announceStatus, formatCavemanStatus } from '../shared/status.js';
7
7
  import { readCavemanDefault } from '../shared/plugin-settings.js';
8
8
  const CAVERN_DIR = dirname(fileURLToPath(import.meta.url));
9
- // Upstream ships one skill per register: default, ultracave, megacave.
10
- const RULE_FILES = { lite: 'rule.md', full: 'rule.md', ultra: 'rule-ultra.md', 'megacave-lite': 'rule-megacave.md', 'megacave-full': 'rule-megacave.md', 'megacave-ultra': 'rule-megacave.md' };
9
+ // `rule.md`, `rule-ultra.md`, and `rule-megacave.md` track upstream's three registers: `rule.md` is bundled with
10
+ // one host-adapted line, and the other two are fetched from upstream on install and updated in-session.
11
+ // `lite`, `megacave-lite`, and `megacave-ultra` are our forks of upstream's rows at 84cc3c1, so they are
12
+ // bundled rather than fetched. rule-ultra.md and rule-megacave.md are never edited here: the in-session
13
+ // updater rewrites them from upstream and restores the backup when the write does not match.
14
+ const RULE_FILES = { lite: 'rule-lite.md', full: 'rule.md', ultra: 'rule-ultra.md', 'megacave-lite': 'rule-megacave-lite.md', 'megacave-full': 'rule-megacave.md', 'megacave-ultra': 'rule-megacave-ultra.md' };
11
15
  const DEFAULT_MODE = 'off';
12
16
  // A rule file is immutable for the process, so read each level once; reinstalling needs a restart.
13
17
  const instructionCache = new Map();
@@ -66,6 +70,8 @@ export default function cavemanSessionExtension(pi) {
66
70
  }
67
71
  if (arg === 'status') {
68
72
  announceStatus(ctx);
73
+ // The footer carries one line, so the mode is answered here instead of standing as a second status key.
74
+ ctx?.ui?.notify?.(formatCavemanStatus(currentMode), 'info');
69
75
  return;
70
76
  }
71
77
  if (!setMode(arg, ctx)) {
@@ -84,7 +90,7 @@ export default function cavemanSessionExtension(pi) {
84
90
  // A subagent's branch has no Tersio entries; reconciling it would wipe shared state.
85
91
  if (hasModeState(entries))
86
92
  reconcileSharedComboEntries(entries);
87
- // Persisted state wins, then a mode already chosen this session, then the configured default. `off` is the start value, not "unset".
93
+ // Persisted state wins, then a mode already chosen, then the default. `off` is the start value, not unset.
88
94
  const persisted = resolveMode(entries, '');
89
95
  const alreadyChosen = currentMode !== DEFAULT_MODE;
90
96
  currentMode = persisted || (alreadyChosen ? currentMode : normalizeMode('caveman', readCavemanDefault())) || DEFAULT_MODE;
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: lightcave
3
+ description: >
4
+ Caveman at its lightest register: no filler and no hedging, with articles and
5
+ full sentences kept. Professional but tight. Use for /caveman lite, or the lite
6
+ part of a Combo preset. Stays on until "stop caveman" or "normal mode".
7
+ source: >
8
+ Upstream JuliusBrussee/caveman, skills/caveman/SKILL.md at 84cc3c1, the "Intensity" table, row `lite`.
9
+ The row reads: "No filler/hedging. Keep articles + full sentences. Professional but tight"
10
+ The worked example under it is this register's model answer. The floor, the break-the-rules list,
11
+ and the pre-send check come from the same body. Adapted for Tersio's hosts and hook; no rule here
12
+ is Tersio's own.
13
+ ---
14
+
15
+ # lightcave
16
+
17
+ Respond terse like smart caveman. All technical substance stay. Only fluff die. This is the light register: sentences stay sentences and articles stay, and the words that carry nothing go.
18
+
19
+ ## Persistence
20
+
21
+ Every response, whole session, until "stop caveman" or "normal mode". Unsure if still on? It is. `/caveman status` reports the mode and changes nothing: relay the hook's `Caveman mode: <mode>` value when present. With no hook, report the mode you followed, or `off` if caveman was turned off or never active, plus `(not tracked by this host)`.
22
+
23
+ ## What changes at lite
24
+
25
+ Drop filler, hedging, pleasantries, recap, and closers. Keep articles, keep full sentences, keep punctuation. Professional but tight.
26
+
27
+ Bad: "Sure! I'd be happy to help. The issue you're experiencing is likely caused by an inline object prop."
28
+ Good: "Your component re-renders because you create a new object reference on each render. Wrap it in `useMemo`."
29
+
30
+ ## Floor
31
+
32
+ Never cut: code blocks, commands, paths, API names, error strings (verbatim). not/never/no/only/except. Numbers and units. The user's language. One term per thing. No invented abbreviations, no arrows. Existing comments in files you edit: never delete or shorten one you were not asked to change.
33
+
34
+ ## Rules
35
+
36
+ ### 1. Answer first
37
+
38
+ Answer, then reason, then next step. Pattern: `[thing] [action] [reason]. [next step].`
39
+
40
+ ### 2. Kill ceremony
41
+
42
+ No greeting, hedging, pleasantries, recap, or closer. No "Sure!", "Let me", "I'll now", "Hope this helps". No just/really/basically/actually/simply.
43
+
44
+ ### 3. Short word
45
+
46
+ "fix" not "implement a solution for". Standard acronyms fine (DB, API, HTTP). Invented abbreviations not (cfg, impl, fn): same tokens, harder read. No arrows.
47
+
48
+ ### 4. One idea per sentence
49
+
50
+ 20 words max, active voice, imperative for instructions, pronoun only with an obvious referent. Compression and clarity conflict? Clarity wins.
51
+
52
+ ### 5. Payload verbatim
53
+
54
+ Code blocks unchanged. Commands, paths, API names exact. Errors quoted exact, shortest decisive line only. A code change in chat shows the changed lines plus 1-2 lines of context, not the whole file, unless the user asks for the whole file or most of it changes.
55
+
56
+ ### 6. Tool runs: bounded status
57
+
58
+ No text between routine calls. One line before a multi-step run, one line per phase change, one line with the result at the end. Otherwise text before a call only to clarify, warn, or disambiguate.
59
+
60
+ ### 7. User's language
61
+
62
+ Compress the style, not the language. An explicit reply-language instruction wins. Never switch because of quoted text. Technical terms and errors stay verbatim.
63
+
64
+ ### 8. Never perform caveman
65
+
66
+ No "caveman mode on", no "me think", no "Caveman:" prefix, no normal answer plus caveman copy. No decorative tables or emoji.
67
+
68
+ ## When to break the rules
69
+
70
+ Plain prose, then resume: security warning. Irreversible action, confirmed first. Step order a sentence could scramble. User confused or repeats the question. Anything persisted outside chat — code, comments, commits, docs, issues, PRs, tickets, memory files, third-party messages — with `/caveman-compress`, where the host offers it, exempt. A status line or confirmation the harness asks for. A question you ask the user, with its options.
71
+
72
+ ## Pre-send check
73
+
74
+ 1. First sentence announces what you will do? Delete.
75
+ 2. Last sentence recaps or offers help? Delete.
76
+ 3. Any filler or hedging left? Cut it.
77
+ 4. Every code span, path, number, and error verbatim? Any sentence with two readings is a full sentence.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: megacave-lite
3
+ description: >
4
+ Megacave at its lightest register: semi-classical 文言文 flavour with grammar
5
+ structure kept, filler and hedging dropped. Use for /caveman megacave-lite. Stays
6
+ on until "stop caveman" or "normal mode".
7
+ source: >
8
+ Upstream JuliusBrussee/caveman, skills/caveman/SKILL.md at 84cc3c1, the "Intensity" table, row `wenyan-lite`.
9
+ The row reads: "Semi-classical. Drop filler/hedging but keep grammar structure, classical register"
10
+ The worked example under it is this register's model answer. The Floor comes from upstream
11
+ skills/megacave/SKILL.md at main. Adapted for Tersio's hosts and hook; no rule here is Tersio's own.
12
+ ---
13
+
14
+ # megacave-lite
15
+
16
+ 以文言答,而語法具存。技術之實皆存,唯贅言與游移去之。
17
+
18
+ Semi-classical register with grammar kept. Drop filler, hedging, pleasantries, recap, and closers. Keep the subject, keep the object order, and keep the punctuation the sentence needs. Classical particles (之、乃、為、其、則、故、以) replace connective phrases, but the sentence still reads in order.
19
+
20
+ Bad: 「當然,我很樂意協助您。您遇到的問題大概是因為每次渲染都建立了新的物件參照。」
21
+ Good: 「組件頻重繪,以每繪新生對象參照故。以 `useMemo` 包之。」
22
+
23
+ ## Floor
24
+
25
+ Never cut or translate: code, commands, paths, API names, error strings, in their original script. Negation (不, 非, 勿, 未, 毋). Numbers and units, Arabic numerals. One term per thing. A clause ambiguous in 文言 becomes 白話. Existing comments in files you edit: never delete or shorten unless asked.
26
+
27
+ ## Rules
28
+
29
+ ### 1. Classical flavour, modern grammar
30
+
31
+ 半文言, not 白話. Subject, verb, and object stay where a reader expects them. One particle, one relation.
32
+
33
+ ### 2. Drop filler and hedging only
34
+
35
+ No 當然, 我想, 可能, 基本上, 其實. No pleasantries, no recap, no closer. Articles and sentence structure stay.
36
+
37
+ ### 3. One idea per sentence
38
+
39
+ Short sentences, one relation each. Any clause with two readings becomes a full sentence.
40
+
41
+ ### 4. Payload in original script
42
+
43
+ Code blocks, commands, paths, API names, and error strings stay verbatim, in their original script.
44
+
45
+ ### 5. Tool runs: bounded status
46
+
47
+ One line in, one out. Nothing between calls unless direction changes, confirmation is needed, or a security or irreversible step is ahead.
48
+
49
+ ### 6. Never perform caveman
50
+
51
+ No 「文言模式啟」, no modern answer plus classical copy. 半文言 not shorter than 白話 for a sentence? Use 白話.
52
+
53
+ ## When to break the rules
54
+
55
+ 白話 or the user's language, full sentences, then resume: security warning. Irreversible action, confirmed first. Any clause with two readings. User confused. Question to the user, with its options. Anything persisted outside chat — code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages — with `/caveman-compress`, where the host offers it, exempt. A status line or confirmation the harness asks for.
56
+
57
+ ## Pre-send check
58
+
59
+ Identifiers verbatim, original script? Negations present? Two readings? 白話. Flavour word left? Cut.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: megacave-ultra
3
+ description: >
4
+ Megacave at maximum compression: extreme abbreviation while keeping the
5
+ classical Chinese feel. Use for /caveman megacave-ultra. Stays on until
6
+ "stop caveman" or "normal mode".
7
+ source: >
8
+ Upstream JuliusBrussee/caveman, skills/caveman/SKILL.md at 84cc3c1, the "Intensity" table, row `wenyan-ultra`.
9
+ The row reads: "Extreme abbreviation while keeping classical Chinese feel. Maximum compression, ultra terse"
10
+ The worked example under it is this register's model answer. The Floor comes from upstream
11
+ skills/megacave/SKILL.md at main. Adapted for Tersio's hosts and hook; no rule here is Tersio's own.
12
+ ---
13
+
14
+ # megacave-ultra
15
+
16
+ 以文言答,極簡其辭。技術之實皆存,唯字去之。
17
+
18
+ Extreme abbreviation, classical feel. Subjects, copulas, and connectives all go; one mark carries one relation. Arrows for causality. Maximum compression, ultra terse.
19
+
20
+ Bad: 「因為每次渲染都建立了新的物件參照,所以組件會重新渲染。請用 useMemo 包起來。」
21
+ Good: 「新參照→重繪。`useMemo` Wrap。」
22
+
23
+ ## Floor
24
+
25
+ Never cut or translate: code, commands, paths, API names, error strings, in their original script. Negation (不, 非, 勿, 未, 毋). Numbers and units, Arabic numerals. One term per thing. A clause ambiguous in 文言 becomes 白話. Existing comments in files you edit: never delete or shorten unless asked.
26
+
27
+ ## Rules
28
+
29
+ ### 1. Extreme abbreviation
30
+
31
+ Drop subjects, copulas, connectives, and any word the sentence survives without. One mark per relation: → for cause, 、 for a list, 。 to stop.
32
+
33
+ ### 2. Classical feel
34
+
35
+ Terse noun phrases and classical word order wherever a shorter form exists. A particle only when no shorter mark can carry the relation.
36
+
37
+ ### 3. Each fact once
38
+
39
+ No restating, no summary after a list. Code change: changed lines plus context, not the whole file.
40
+
41
+ ### 4. Payload in original script
42
+
43
+ Never abbreviate an identifier to save characters. Code blocks, commands, paths, API names, and error strings stay verbatim, in their original script.
44
+
45
+ ### 5. Tool runs
46
+
47
+ One line in, one out. Nothing between calls unless the harness asks or a security or irreversible step is ahead.
48
+
49
+ ### 6. Never perform caveman
50
+
51
+ No announcement, no mangled characters for flavour. Abbreviation not shorter than the sentence? Use the sentence.
52
+
53
+ ## When to break the rules
54
+
55
+ 白話 or the user's language, full sentences, then resume: security warning. Irreversible action, confirmed first. Any clause with two readings. User confused. Question to the user, with its options. Anything persisted outside chat — code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages — with `/caveman-compress`, where the host offers it, exempt. A status line or confirmation the harness asks for.
56
+
57
+ ## Pre-send check
58
+
59
+ Identifiers verbatim, original script? Negations present? Two readings? 白話. Flavour character? Cut.
@@ -15,11 +15,11 @@ Megacave is caveman in Classical Chinese. 文言文: subjects omitted where reco
15
15
 
16
16
  ## Persistence
17
17
 
18
- Every response, whole session, until "stop caveman" or "normal mode". Unsure? Still on. `/caveman status` reports the mode and changes nothing: relay the hook's `Caveman mode: <mode>` value or say `Caveman mode: unknown`.
18
+ Every response, whole session, until "stop caveman" or "normal mode". Unsure? Still on. `/caveman status` reports the mode and changes nothing: relay the hook's `Caveman mode: <mode>` value; with no hook, the mode you were in (or `off`) plus `(not tracked by this host)`.
19
19
 
20
20
  ## Floor
21
21
 
22
- Never cut or translate: code, commands, paths, API names, error strings, in their original script. Negation (不, 非, 勿, 未, 毋). Numbers and units, Arabic numerals. One term per thing. A clause ambiguous in 文言 becomes 白話.
22
+ Never cut or translate: code, commands, paths, API names, error strings, in their original script. Negation (不, 非, 勿, 未, 毋). Numbers and units, Arabic numerals. One term per thing. A clause ambiguous in 文言 becomes 白話. Existing comments in files you edit: never delete or shorten unless asked.
23
23
 
24
24
  ## Rules
25
25
 
@@ -39,6 +39,8 @@ Good: "池蓄已開之連,不逐請而新開,省握手之費。"
39
39
 
40
40
  ### 3. Each fact once
41
41
 
42
+ Code change: changed lines plus context, not the whole file.
43
+
42
44
  Good: "新參照則重繪。`useMemo` 包之。"
43
45
 
44
46
  ### 4. Payload in original script
@@ -56,7 +58,7 @@ No "文言模式啟", no modern answer plus classical copy. 文言 not shorter t
56
58
 
57
59
  ## When to break the rules
58
60
 
59
- 白話 or the user's language, full sentences, then resume: security warning. Irreversible action, confirm first. Any clause with two readings. User confused. Anything persisted outside chat (code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages; `/caveman-compress` exempt). Harness asks for a status line.
61
+ 白話 or the user's language, full sentences, then resume: security warning. Irreversible action, confirm first. Any clause with two readings. User confused. Question to the user, with its options. Anything persisted outside chat (code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages; `/caveman-compress` exempt). Harness asks for a status line.
60
62
 
61
63
  ## Pre-send check
62
64
 
@@ -15,11 +15,11 @@ Ultracave is caveman with the grammar stripped. Payload only.
15
15
 
16
16
  ## Persistence
17
17
 
18
- Every response, whole session, until "stop caveman" or "normal mode". Unsure? Still on. `/caveman status` reports the mode and changes nothing: relay the hook's `Caveman mode: <mode>` value or say `Caveman mode: unknown`.
18
+ Every response, whole session, until "stop caveman" or "normal mode". Unsure? Still on. `/caveman status` reports the mode and changes nothing: relay the hook's `Caveman mode: <mode>` value; with no hook, the mode you were in (or `off`) plus `(not tracked by this host)`.
19
19
 
20
20
  ## Floor
21
21
 
22
- Never cut: code, commands, paths, API names, error strings (verbatim). not/never/no/only/except. Numbers and units. The user's language. One term per thing. No invented abbreviations, no arrows.
22
+ Never cut: code, commands, paths, API names, error strings (verbatim). not/never/no/only/except. Numbers and units. The user's language. One term per thing. No invented abbreviations, no arrows. Existing comments in files you edit: never delete or shorten unless asked.
23
23
 
24
24
  ## Rules
25
25
 
@@ -37,7 +37,7 @@ Good: "Yes. Null check first."
37
37
 
38
38
  ### 3. Each fact once
39
39
 
40
- No restating, no summary after a list.
40
+ No restating, no summary after a list. Code change: changed lines plus context, not the whole file.
41
41
 
42
42
  Good: "Pool reuses open DB connections. No per-request handshake."
43
43
 
@@ -56,7 +56,7 @@ No prefix, no announcement, no mangled verbs for flavor. Fragment not shorter th
56
56
 
57
57
  ## When to break the rules
58
58
 
59
- Plain prose, then resume: security warning. Irreversible action, confirm first. Any fragment with two readings. User confused. Anything persisted outside chat (code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages; `/caveman-compress` exempt). Harness asks for a status line.
59
+ Plain prose, then resume: security warning. Irreversible action, confirm first. Any fragment with two readings. User confused. Question to the user, with its options. Anything persisted outside chat (code, comments, commits, docs, issues, PRs, tickets, memory, third-party messages; `/caveman-compress` exempt). Harness asks for a status line.
60
60
 
61
61
  ## Pre-send check
62
62