@ashx-j/lunr 0.2.12 → 0.2.13

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 (43) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/catalog/models.json +1 -1
  3. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  4. package/dist/catalog/providers/fireworks.json +1 -1
  5. package/dist/catalog/providers/opencode-go.json +1 -1
  6. package/dist/catalog/providers/opencode.json +1 -1
  7. package/dist/catalog/providers/openrouter.json +1 -1
  8. package/dist/catalog/providers/together.json +1 -1
  9. package/dist/catalog/publication.json +3 -3
  10. package/dist/core/context-breakdown.d.ts +3 -1
  11. package/dist/core/context-breakdown.d.ts.map +1 -1
  12. package/dist/core/context-breakdown.js +5 -2
  13. package/dist/core/context-breakdown.js.map +1 -1
  14. package/dist/core/settings-manager.d.ts +7 -0
  15. package/dist/core/settings-manager.d.ts.map +1 -1
  16. package/dist/core/settings-manager.js +13 -0
  17. package/dist/core/settings-manager.js.map +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  22. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  23. package/dist/modes/interactive/components/settings-selector.js +105 -89
  24. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  25. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  26. package/dist/modes/interactive/interactive-mode.js +16 -3
  27. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  28. package/dist/modes/interactive/skill-tag-autocomplete.d.ts +13 -0
  29. package/dist/modes/interactive/skill-tag-autocomplete.d.ts.map +1 -0
  30. package/dist/modes/interactive/skill-tag-autocomplete.js +72 -0
  31. package/dist/modes/interactive/skill-tag-autocomplete.js.map +1 -0
  32. package/docs/settings.md +1 -0
  33. package/docs/skills.md +10 -0
  34. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  35. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  36. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  37. package/examples/extensions/gondolin/package-lock.json +2 -2
  38. package/examples/extensions/gondolin/package.json +1 -1
  39. package/examples/extensions/sandbox/package-lock.json +2 -2
  40. package/examples/extensions/sandbox/package.json +1 -1
  41. package/examples/extensions/with-deps/package-lock.json +2 -2
  42. package/examples/extensions/with-deps/package.json +1 -1
  43. package/package.json +4 -4
@@ -2,6 +2,7 @@ import { Container, getCapabilities, getKeybindings, Input, SelectList, Settings
2
2
  import { getCustomizeBridge } from "../../../core/customize.js";
3
3
  import { formatHttpIdleTimeoutMs, HTTP_IDLE_TIMEOUT_CHOICES } from "../../../core/http-dispatcher.js";
4
4
  import { MEMORY_CHAR_CAP_DEFAULT, MEMORY_CHAR_CAP_MAX, MEMORY_CHAR_CAP_MIN } from "../../../core/memory-cap.js";
5
+ import { SKILL_TAG_CHARACTERS, } from "../../../core/settings-manager.js";
5
6
  import { getSelectListTheme, getSettingsListTheme, parseAutoThemeSetting, theme, } from "../theme/theme.js";
6
7
  import { DynamicBorder } from "./dynamic-border.js";
7
8
  import { keyDisplayText } from "./keybinding-hints.js";
@@ -28,17 +29,17 @@ const MODEL_TIER_ROWS = [
28
29
  {
29
30
  tier: "light",
30
31
  label: "Light tier model",
31
- description: "Cheap/fast model for simple subagent tasks (lookups, formatting)",
32
+ description: "Fast, low-cost model for simple subagent tasks",
32
33
  },
33
34
  {
34
35
  tier: "standard",
35
36
  label: "Standard tier model",
36
- description: "Mid-tier model for typical coding subagent tasks",
37
+ description: "Balanced model for everyday coding tasks",
37
38
  },
38
39
  {
39
40
  tier: "heavy",
40
41
  label: "Heavy tier model",
41
- description: "Strongest model for deep reasoning and complex debugging subagents",
42
+ description: "Strong model for complex reasoning and debugging",
42
43
  },
43
44
  ];
44
45
  /**
@@ -64,7 +65,7 @@ class ModelTiersSubmenu extends Container {
64
65
  {
65
66
  id: "enabled",
66
67
  label: "Enable model tiers",
67
- description: "Route subagents to per-tier models. An explicit model choice overrides the tier; tiers without a model inherit the parent model.",
68
+ description: "Route subagent work by model tier",
68
69
  currentValue: this.state.enabled ? "on" : "off",
69
70
  values: ["on", "off"],
70
71
  },
@@ -83,11 +84,15 @@ class ModelTiersSubmenu extends Container {
83
84
  {
84
85
  id: `${tier}-thinking`,
85
86
  label: `${row.label.replace(" model", "")} thinking`,
86
- description: "Reasoning depth for this tier. Inherit uses the parent session level.",
87
+ description: "Reasoning level for this tier",
87
88
  currentValue: this.state[tKey] ?? "inherit",
88
89
  disabled: () => !this.state.enabled,
89
- submenu: (_currentValue, done) => new SelectSubmenu(`${row.label} thinking`, "Unset inherits the parent session thinking level.", [
90
- { value: "inherit", label: "inherit", description: "Use the parent session thinking level" },
90
+ submenu: (_currentValue, done) => new SelectSubmenu(`${row.label} thinking`, "Inherit uses the parent session's reasoning level", [
91
+ {
92
+ value: "inherit",
93
+ label: "inherit",
94
+ description: "Use the parent session's reasoning level",
95
+ },
91
96
  ...callbacks.getTierThinkingLevels(tier).map((level) => ({
92
97
  value: level,
93
98
  label: level,
@@ -134,7 +139,7 @@ class MemoryCharCapSubmenu extends Container {
134
139
  super();
135
140
  this.addChild(new Text(theme.bold(theme.fg("accent", "Memory Character Cap")), 0, 0));
136
141
  this.addChild(new Spacer(1));
137
- this.addChild(new Text(theme.fg("muted", `Max characters in the memory file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}).`), 0, 0));
142
+ this.addChild(new Text(theme.fg("muted", `Maximum agent memory size (${MEMORY_CHAR_CAP_MIN} to ${MEMORY_CHAR_CAP_MAX} characters, default ${MEMORY_CHAR_CAP_DEFAULT})`), 0, 0));
138
143
  this.addChild(new Spacer(1));
139
144
  this.input = new Input();
140
145
  this.input.setValue(currentValue);
@@ -169,84 +174,84 @@ class CustomizeSubmenu extends Container {
169
174
  {
170
175
  id: "gutter-rail",
171
176
  label: "Gutter rail",
172
- description: "Render a thin left │ rail spanning each turn, closing with ╰.",
177
+ description: "Turn boundary rail",
173
178
  currentValue: (bridge?.getGutterRail() ?? true) ? "on" : "off",
174
179
  values: ["on", "off"],
175
180
  },
176
181
  {
177
182
  id: "prompt-symbol",
178
183
  label: "Prompt symbol",
179
- description: "Show the ☾ › prompt glyph on the editor's first line.",
184
+ description: "Moon prompt glyph",
180
185
  currentValue: (bridge?.getPromptSymbol() ?? true) ? "on" : "off",
181
186
  values: ["on", "off"],
182
187
  },
183
188
  {
184
189
  id: "footer-mcp",
185
190
  label: "Footer: MCP status",
186
- description: "Show the MCP server status segment in the footer stats line.",
191
+ description: "MCP server status",
187
192
  currentValue: (bridge?.getFooterMcp() ?? true) ? "on" : "off",
188
193
  values: ["on", "off"],
189
194
  },
190
195
  {
191
196
  id: "footer-lsp",
192
197
  label: "Footer: LSP status",
193
- description: "Show the LSP status segment in the footer stats line.",
198
+ description: "Language server status",
194
199
  currentValue: (bridge?.getFooterLsp() ?? false) ? "on" : "off",
195
200
  values: ["on", "off"],
196
201
  },
197
202
  {
198
203
  id: "footer-context",
199
204
  label: "Footer: context meter",
200
- description: "Show the context-usage pct/window segment in the footer stats line.",
205
+ description: "Context usage",
201
206
  currentValue: (bridge?.getFooterContext() ?? true) ? "on" : "off",
202
207
  values: ["on", "off"],
203
208
  },
204
209
  {
205
210
  id: "footer-tokens",
206
211
  label: "Footer: token counter",
207
- description: "Show the ↑in ↓out token totals segment in the footer stats line.",
212
+ description: "Input and output token counts",
208
213
  currentValue: (bridge?.getFooterTokens() ?? true) ? "on" : "off",
209
214
  values: ["on", "off"],
210
215
  },
211
216
  {
212
217
  id: "footer-cache-hit-rate",
213
218
  label: "Footer: cache hit rate",
214
- description: "Show the latest prompt cache-hit rate when cache usage is reported.",
219
+ description: "Latest prompt cache hit rate",
215
220
  currentValue: (bridge?.getFooterCacheHitRate() ?? true) ? "on" : "off",
216
221
  values: ["on", "off"],
217
222
  },
218
223
  {
219
224
  id: "footer-tps",
220
225
  label: "Footer: TPS counter",
221
- description: "Show the ✓ 174.0 t/s · tokens-in-time segment in the footer stats line.",
226
+ description: "Token generation speed",
222
227
  currentValue: (bridge?.getFooterTps() ?? true) ? "on" : "off",
223
228
  values: ["on", "off"],
224
229
  },
225
230
  {
226
231
  id: "footer-statuses",
227
232
  label: "Footer: feature statuses",
228
- description: "Show the plan/goal/swarm status segments in the footer stats line.",
233
+ description: "Active plan, goal, and swarm status",
229
234
  currentValue: (bridge?.getFooterStatuses() ?? true) ? "on" : "off",
230
235
  values: ["on", "off"],
231
236
  },
232
237
  {
233
238
  id: "footer-git",
234
239
  label: "Footer: git branch",
235
- description: "Show the current git branch and added/removed line counts in the footer stats line.",
240
+ description: "Git branch and line changes",
236
241
  currentValue: (bridge?.getFooterGit() ?? true) ? "on" : "off",
237
242
  values: ["on", "off"],
238
243
  },
239
244
  {
240
245
  id: "footer-plan",
241
246
  label: "Footer: plan usage",
242
- description: "Show the live subscription usage percent when the current model is on a plan.",
247
+ description: "Subscription usage percentage",
243
248
  currentValue: (bridge?.getFooterPlan() ?? true) ? "on" : "off",
244
249
  values: ["on", "off"],
245
250
  },
246
251
  {
247
252
  id: "footer-plan-bar",
248
253
  label: "Footer: plan bar",
249
- description: "Show the filled █░ bar next to the plan percent. Off keeps the percent only.",
254
+ description: "Bar beside the subscription usage percentage",
250
255
  currentValue: (bridge?.getFooterPlanBar() ?? true) ? "on" : "off",
251
256
  values: ["on", "off"],
252
257
  },
@@ -308,8 +313,7 @@ class RollbackSubmenu extends Container {
308
313
  {
309
314
  id: "rollback-enabled",
310
315
  label: "Rollback enabled",
311
- description: "Copy files before edits so /rollback can restore them. Uses extra disk + processing." +
312
- (sessionForceEnabled ? " (forced on by auto mode)" : ""),
316
+ description: `Save file snapshots for /rollback${sessionForceEnabled ? ". Always on in Auto mode" : ""}`,
313
317
  currentValue: this.enabled ? "on" : "off",
314
318
  values: ["on", "off"],
315
319
  disabled: () => sessionForceEnabled,
@@ -317,7 +321,7 @@ class RollbackSubmenu extends Container {
317
321
  {
318
322
  id: "rollback-turns",
319
323
  label: "Rollback turns",
320
- description: `How many turns of snapshots to retain (1-20, default 2).`,
324
+ description: "Number of turns kept for rollback",
321
325
  currentValue: String(config.rollbackTurns),
322
326
  disabled: () => !this.enabled,
323
327
  submenu: (currentValue, submenuDone) => new RollbackTurnsSubmenu(currentValue, submenuDone),
@@ -325,24 +329,24 @@ class RollbackSubmenu extends Container {
325
329
  {
326
330
  id: "rollback-capture",
327
331
  label: "Capture mode",
328
- description: "How snapshots are taken: copies = restore edited files + delete tool-created files, hybrid = also delete files created outside tools (tree scope), shadow-git = hidden git repo (needs git).",
332
+ description: "How rollback snapshots are stored",
329
333
  currentValue: config.rollbackCapture,
330
334
  disabled: () => !this.enabled,
331
- submenu: (currentValue, submenuDone) => new SelectSubmenu("Rollback Capture Mode", "How file snapshots are captured before edits.", [
335
+ submenu: (currentValue, submenuDone) => new SelectSubmenu("Rollback Capture Mode", "Snapshot storage method", [
332
336
  {
333
337
  value: "copies",
334
338
  label: "copies",
335
- description: "fast; restores edits, deletes tool-created files",
339
+ description: "File copies for tool edits and created files",
336
340
  },
337
341
  {
338
342
  value: "hybrid",
339
343
  label: "hybrid",
340
- description: "also deletes files created outside tools (tree scope)",
344
+ description: "Track files created outside tools with tree scope",
341
345
  },
342
346
  {
343
347
  value: "shadow-git",
344
348
  label: "shadow-git",
345
- description: "needs git, hidden repo — deferred, falls back to copies",
349
+ description: "Reserved mode; currently falls back to copies",
346
350
  },
347
351
  ], currentValue, (value) => {
348
352
  callbacks.onRollbackCaptureChange(value);
@@ -352,15 +356,15 @@ class RollbackSubmenu extends Container {
352
356
  {
353
357
  id: "rollback-scope",
354
358
  label: "Rollback scope",
355
- description: "tools = only edit/write changes; tree = also catches bash side-effects via git status (slower on large repos).",
359
+ description: "Which file changes rollback tracks",
356
360
  currentValue: config.rollbackScope,
357
361
  disabled: () => !this.enabled,
358
- submenu: (currentValue, submenuDone) => new SelectSubmenu("Rollback Scope", "What file changes to snapshot.", [
359
- { value: "tools", label: "tools", description: "only edit/write tool changes" },
362
+ submenu: (currentValue, submenuDone) => new SelectSubmenu("Rollback Scope", "File changes included in snapshots", [
363
+ { value: "tools", label: "tools", description: "Changes made by edit and write tools" },
360
364
  {
361
365
  value: "tree",
362
366
  label: "tree",
363
- description: "also catches bash side-effects; slower on large repos",
367
+ description: "Tool and shell changes across the repository",
364
368
  },
365
369
  ], currentValue, (value) => {
366
370
  callbacks.onRollbackScopeChange(value);
@@ -392,7 +396,7 @@ class RollbackTurnsSubmenu extends Container {
392
396
  super();
393
397
  this.addChild(new Text(theme.bold(theme.fg("accent", "Rollback Turns")), 0, 0));
394
398
  this.addChild(new Spacer(1));
395
- this.addChild(new Text(theme.fg("muted", "How many turns of snapshots to retain (1-20, default 2)."), 0, 0));
399
+ this.addChild(new Text(theme.fg("muted", "Number of turns kept for rollback (1 to 20, default 2)"), 0, 0));
396
400
  this.addChild(new Spacer(1));
397
401
  this.input = new Input();
398
402
  this.input.setValue(currentValue);
@@ -463,8 +467,8 @@ class SubscriptionActionSubmenu extends Container {
463
467
  id: "set-active",
464
468
  label: "Set active",
465
469
  description: subs.autoManage()
466
- ? "Manual switching is disabled while Auto-manage subscriptions is on."
467
- : "Use this key for new requests.",
470
+ ? "Turn off automatic key rotation to switch keys"
471
+ : "Use this key for new requests",
468
472
  currentValue: row.active ? "already active" : "activate",
469
473
  values: ["activate"],
470
474
  disabled: () => subs.autoManage() || row.active,
@@ -472,7 +476,7 @@ class SubscriptionActionSubmenu extends Container {
472
476
  {
473
477
  id: "rename",
474
478
  label: "Rename",
475
- description: "Display name for this key.",
479
+ description: "Change the key's display name",
476
480
  currentValue: row.name,
477
481
  submenu: (currentValue, renameDone) => new SubscriptionRenameSubmenu(currentValue, (name) => {
478
482
  if (name === undefined) {
@@ -491,7 +495,7 @@ class SubscriptionActionSubmenu extends Container {
491
495
  label: "Clear exhausted flag",
492
496
  description: row.exhaustedUntil !== undefined
493
497
  ? `Marked exhausted until ${formatSubscriptionExhaustedUntil(row.exhaustedUntil)}.`
494
- : "Only available for keys marked exhausted.",
498
+ : "Unavailable until the key is marked exhausted",
495
499
  currentValue: "clear",
496
500
  values: ["clear"],
497
501
  disabled: () => row.exhaustedUntil === undefined,
@@ -499,9 +503,9 @@ class SubscriptionActionSubmenu extends Container {
499
503
  {
500
504
  id: "remove",
501
505
  label: "Remove",
502
- description: "Delete this key. Removing the provider's last key logs it out completely.",
506
+ description: "Delete this stored key",
503
507
  currentValue: "remove…",
504
- submenu: (_currentValue, confirmDone) => new SelectSubmenu("Remove Subscription", `Remove "${row.name}" (${row.providerName})? Removing the provider's last key logs it out.`, [
508
+ submenu: (_currentValue, confirmDone) => new SelectSubmenu("Remove Subscription", `Delete "${row.name}" from ${row.providerName}? The last key also logs out the provider.`, [
505
509
  { value: "cancel", label: "Cancel" },
506
510
  { value: "remove", label: "Remove key" },
507
511
  ], "cancel", (value) => {
@@ -651,7 +655,7 @@ function singleModeThemeItems(availableThemes) {
651
655
  {
652
656
  value: AUTOMATIC_THEME_VALUE,
653
657
  label: "Automatic",
654
- description: "Use separate themes for light and dark terminal appearance",
658
+ description: "Follow the terminal's light or dark appearance",
655
659
  },
656
660
  ...themeItems(availableThemes),
657
661
  ];
@@ -713,7 +717,7 @@ class ThemeSubmenu extends Container {
713
717
  }
714
718
  showSingleMenu() {
715
719
  this.mode = "single";
716
- const menu = new SelectSubmenu("Theme", "Select a theme, or choose Automatic to follow terminal appearance.", singleModeThemeItems(this.availableThemes), this.singleTheme, (value) => {
720
+ const menu = new SelectSubmenu("Theme", "Choose a theme or follow terminal appearance", singleModeThemeItems(this.availableThemes), this.singleTheme, (value) => {
717
721
  if (value === AUTOMATIC_THEME_VALUE) {
718
722
  this.mode = "automatic";
719
723
  this.callbacks.onThemePreview?.(this.getThemeSetting());
@@ -732,16 +736,16 @@ class ThemeSubmenu extends Container {
732
736
  const content = new Container();
733
737
  content.addChild(new Text(theme.bold(theme.fg("accent", "Automatic Theme")), 0, 0));
734
738
  content.addChild(new Spacer(1));
735
- content.addChild(new Text(theme.fg("muted", "Choose themes for terminal light and dark appearance."), 0, 0));
739
+ content.addChild(new Text(theme.fg("muted", "Use different themes for light and dark terminals."), 0, 0));
736
740
  content.addChild(new Text(theme.fg("muted", "Light/dark detection requires terminal support."), 0, 0));
737
741
  content.addChild(new Spacer(1));
738
742
  const items = [
739
743
  {
740
744
  id: "light-theme",
741
745
  label: "Light theme",
742
- description: "Theme to use in automatic mode when the terminal is light",
746
+ description: "Theme for light terminals",
743
747
  currentValue: this.lightTheme,
744
- submenu: (currentValue, done) => this.createThemeSelect("Light Theme", "Select the theme to use for light terminal appearance", currentValue, done, (value) => {
748
+ submenu: (currentValue, done) => this.createThemeSelect("Light Theme", "Theme for light terminals", currentValue, done, (value) => {
745
749
  this.lightTheme = value;
746
750
  this.callbacks.onThemePreview?.(this.getThemeSetting());
747
751
  done(value);
@@ -750,9 +754,9 @@ class ThemeSubmenu extends Container {
750
754
  {
751
755
  id: "dark-theme",
752
756
  label: "Dark theme",
753
- description: "Theme to use in automatic mode when the terminal is dark",
757
+ description: "Theme for dark terminals",
754
758
  currentValue: this.darkTheme,
755
- submenu: (currentValue, done) => this.createThemeSelect("Dark Theme", "Select the theme to use for dark terminal appearance", currentValue, done, (value) => {
759
+ submenu: (currentValue, done) => this.createThemeSelect("Dark Theme", "Theme for dark terminals", currentValue, done, (value) => {
756
760
  this.darkTheme = value;
757
761
  this.callbacks.onThemePreview?.(this.getThemeSetting());
758
762
  done(value);
@@ -761,14 +765,14 @@ class ThemeSubmenu extends Container {
761
765
  {
762
766
  id: "apply",
763
767
  label: "Apply",
764
- description: "Save and go back",
768
+ description: "Save theme settings",
765
769
  currentValue: "save and go back",
766
770
  values: ["save and go back"],
767
771
  },
768
772
  {
769
773
  id: "single-mode",
770
774
  label: "Change mode",
771
- description: "Switch to one theme for light and dark",
775
+ description: "Use one theme for all terminal appearances",
772
776
  currentValue: "switch to single theme",
773
777
  values: ["switch to single theme"],
774
778
  },
@@ -826,42 +830,42 @@ export class SettingsSelectorComponent extends Container {
826
830
  {
827
831
  id: "autocompact",
828
832
  label: "Auto-compact",
829
- description: "Automatically compact context when it gets too large",
833
+ description: "Compact context before it reaches the model limit",
830
834
  currentValue: config.autoCompact ? "true" : "false",
831
835
  values: ["true", "false"],
832
836
  },
833
837
  {
834
838
  id: "steering-mode",
835
839
  label: "Steering mode",
836
- description: "Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.",
840
+ description: "How new messages interrupt a streaming response",
837
841
  currentValue: config.steeringMode,
838
842
  values: ["one-at-a-time", "all"],
839
843
  },
840
844
  {
841
845
  id: "follow-up-mode",
842
846
  label: "Follow-up mode",
843
- description: `${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,
847
+ description: `How ${followUpKey} messages run after the current response`,
844
848
  currentValue: config.followUpMode,
845
849
  values: ["one-at-a-time", "all"],
846
850
  },
847
851
  {
848
852
  id: "transport",
849
853
  label: "Transport",
850
- description: "Preferred transport for providers that support multiple transports",
854
+ description: "Connection method for supported providers",
851
855
  currentValue: config.transport,
852
856
  values: ["sse", "websocket", "websocket-cached", "auto"],
853
857
  },
854
858
  {
855
859
  id: "http-idle-timeout",
856
860
  label: "HTTP idle timeout",
857
- description: "Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.",
861
+ description: "Time before an inactive HTTP request times out",
858
862
  currentValue: formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),
859
863
  values: HTTP_IDLE_TIMEOUT_CHOICES.map((choice) => choice.label),
860
864
  },
861
865
  {
862
866
  id: "hide-thinking",
863
867
  label: "Hide thinking",
864
- description: "Hide thinking blocks in assistant responses",
868
+ description: "Thinking block visibility",
865
869
  currentValue: config.hideThinkingBlock ? "true" : "false",
866
870
  values: ["true", "false"],
867
871
  },
@@ -870,7 +874,7 @@ export class SettingsSelectorComponent extends Container {
870
874
  // "✻ Thought for Xs" + first sentence. Disabled when thinking is hidden.
871
875
  id: "thinking-collapse",
872
876
  label: "Collapse thinking",
873
- description: "Collapse completed thinking blocks to a short summary",
877
+ description: "Short summaries for completed thinking",
874
878
  currentValue: config.thinkingCollapse ? "true" : "false",
875
879
  values: ["true", "false"],
876
880
  disabled: () => config.hideThinkingBlock,
@@ -878,7 +882,7 @@ export class SettingsSelectorComponent extends Container {
878
882
  {
879
883
  id: "cache-miss-notices",
880
884
  label: "Cache miss notices",
881
- description: "Show transcript notices for significant prompt-cache misses",
885
+ description: "Prompt cache miss notices in the transcript",
882
886
  currentValue: config.showCacheMissNotices ? "true" : "false",
883
887
  values: ["true", "false"],
884
888
  },
@@ -887,35 +891,35 @@ export class SettingsSelectorComponent extends Container {
887
891
  // applies; the row displays "short" as the implicit default.
888
892
  id: "cache-retention",
889
893
  label: "Cache retention",
890
- description: "Prompt-cache TTL: short (5 min), long (1h where supported), or none",
894
+ description: "Prompt cache lifetime",
891
895
  currentValue: config.cacheRetention,
892
896
  values: ["short", "long", "none"],
893
897
  },
894
898
  {
895
899
  id: "quiet-startup",
896
900
  label: "Quiet startup",
897
- description: "Disable verbose printing at startup",
901
+ description: "Startup log visibility",
898
902
  currentValue: config.quietStartup ? "true" : "false",
899
903
  values: ["true", "false"],
900
904
  },
901
905
  {
902
906
  id: "smooth-streaming",
903
907
  label: "Smooth streaming",
904
- description: "Reveal responses grapheme by grapheme (~30 FPS typewriter)",
908
+ description: "Typewriter-style response streaming",
905
909
  currentValue: config.smoothStreaming ? "true" : "false",
906
910
  values: ["true", "false"],
907
911
  },
908
912
  {
909
913
  id: "agent-memory",
910
914
  label: "Agent memory",
911
- description: "Inject durable facts and allow the model to add, inspect, and remove them.",
915
+ description: "Durable facts the agent can manage",
912
916
  currentValue: config.memoryEnabled ? "on" : "off",
913
917
  values: ["on", "off"],
914
918
  },
915
919
  {
916
920
  id: "memory-char-cap",
917
921
  label: "Memory character cap",
918
- description: `Max characters in the durable-facts memory file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}). Also settable via /memory-char-cap.`,
922
+ description: "Maximum agent memory size",
919
923
  currentValue: String(config.memoryCharCap),
920
924
  submenu: (currentValue, submenuDone) => new MemoryCharCapSubmenu(currentValue, submenuDone),
921
925
  },
@@ -923,52 +927,52 @@ export class SettingsSelectorComponent extends Container {
923
927
  id: "search-curator",
924
928
  label: "Search curator",
925
929
  description: curatorAvailable
926
- ? "pi-web-access search curator: off = raw results, on = browser curator with summary draft, auto-summary = summary without the curator. Also settable via /curator."
927
- : "pi-web-access is not loaded; the search curator is unavailable.",
930
+ ? "Web search review and summary mode"
931
+ : "Unavailable because web access is not loaded",
928
932
  currentValue: config.searchCurator ?? "unavailable",
929
933
  values: curatorAvailable ? SEARCH_CURATOR_VALUES : undefined,
930
934
  },
931
935
  {
932
936
  id: "session-retention-days",
933
937
  label: "Session retention",
934
- description: "Auto-delete session files older than N days at launch (0 = keep forever)",
938
+ description: "How long session files are kept",
935
939
  currentValue: String(config.sessionRetentionDays),
936
940
  values: ["0", "7", "14", "30", "60", "90", "365"],
937
941
  },
938
942
  {
939
943
  id: "default-project-trust",
940
944
  label: "Default project trust",
941
- description: "Fallback behavior when no extension or saved trust decision decides project trust",
945
+ description: "Trust choice when a project has no saved decision",
942
946
  currentValue: DEFAULT_PROJECT_TRUST_LABELS[config.defaultProjectTrust],
943
947
  values: Object.values(DEFAULT_PROJECT_TRUST_LABELS),
944
948
  },
945
949
  {
946
950
  id: "default-permission-mode",
947
951
  label: "Default permission mode",
948
- description: "Permission mode new sessions start with: manual = approve every action, yolo = auto-approve tools, plan = read-only, auto = fully autonomous. Change per-session with /mode or Shift+Tab.",
952
+ description: "Starting permission mode for new sessions",
949
953
  currentValue: config.defaultPermissionMode,
950
954
  values: ["manual", "yolo", "plan", "auto"],
951
955
  },
952
956
  {
953
957
  id: "double-escape-action",
954
958
  label: "Double-escape action",
955
- description: "Action when pressing Escape twice with empty editor",
959
+ description: "Action for double Escape in an empty editor",
956
960
  currentValue: config.doubleEscapeAction,
957
961
  values: ["tree", "fork", "none"],
958
962
  },
959
963
  {
960
964
  id: "tree-filter-mode",
961
965
  label: "Tree filter mode",
962
- description: "Default filter when opening /tree",
966
+ description: "Default /tree filter",
963
967
  currentValue: config.treeFilterMode,
964
968
  values: ["default", "no-tools", "user-only", "labeled-only", "all"],
965
969
  },
966
970
  {
967
971
  id: "thinking",
968
972
  label: "Thinking level",
969
- description: "Reasoning depth for thinking-capable models",
973
+ description: "Reasoning level for supported models",
970
974
  currentValue: config.thinkingLevel,
971
- submenu: (currentValue, done) => new SelectSubmenu("Thinking Level", "Select reasoning depth for thinking-capable models", config.availableThinkingLevels.map((level) => ({
975
+ submenu: (currentValue, done) => new SelectSubmenu("Thinking Level", "Reasoning level for supported models", config.availableThinkingLevels.map((level) => ({
972
976
  value: level,
973
977
  label: level,
974
978
  description: THINKING_DESCRIPTIONS[level],
@@ -980,21 +984,21 @@ export class SettingsSelectorComponent extends Container {
980
984
  {
981
985
  id: "theme",
982
986
  label: "Theme",
983
- description: "Color theme for the interface",
987
+ description: "Interface color theme",
984
988
  currentValue: config.currentTheme,
985
989
  submenu: (currentValue, done) => new ThemeSubmenu(currentValue, config.terminalTheme, config.availableThemes, callbacks, done),
986
990
  },
987
991
  {
988
992
  id: "model-tiers",
989
993
  label: "Model tiers",
990
- description: "Route subagents to light/standard/heavy tier models. An explicit model choice overrides the tier.",
994
+ description: "Subagent model routing",
991
995
  currentValue: config.modelTiers.enabled ? "on" : "off",
992
996
  submenu: (currentValue, done) => new ModelTiersSubmenu(currentValue, config.modelTiers, callbacks, done),
993
997
  },
994
998
  {
995
999
  id: "plan-usage-window",
996
1000
  label: "Plan usage window",
997
- description: "Preferred subscription window for the footer bar. Missing 5h falls back to weekly.",
1001
+ description: "Subscription usage period shown in the footer",
998
1002
  currentValue: config.planUsageWindow,
999
1003
  values: ["5h", "weekly"],
1000
1004
  },
@@ -1002,7 +1006,7 @@ export class SettingsSelectorComponent extends Container {
1002
1006
  {
1003
1007
  id: "customize",
1004
1008
  label: "Customize",
1005
- description: "lunR TUI customizations: gutter rail, prompt symbol, footer segments",
1009
+ description: "Interface and footer options",
1006
1010
  currentValue: "configure",
1007
1011
  submenu: (_currentValue, done) => new CustomizeSubmenu(config, callbacks, done),
1008
1012
  },
@@ -1010,7 +1014,7 @@ export class SettingsSelectorComponent extends Container {
1010
1014
  {
1011
1015
  id: "rollback",
1012
1016
  label: "Rollback",
1013
- description: "Pre-edit file snapshots so /rollback can restore them. Capture mode, scope, retention.",
1017
+ description: "Rollback behavior options",
1014
1018
  currentValue: config.rollbackEnabled ? "on" : "off",
1015
1019
  submenu: (currentValue, done) => new RollbackSubmenu(currentValue, config, callbacks, callbacks.isRollbackSessionForceEnabled(), done),
1016
1020
  },
@@ -1018,7 +1022,7 @@ export class SettingsSelectorComponent extends Container {
1018
1022
  {
1019
1023
  id: "auto-manage-subscriptions",
1020
1024
  label: "Auto-manage subscriptions",
1021
- description: "When on, lunr rotates API keys automatically on usage limits and the model selector won't offer manual subscription switching.",
1025
+ description: "Automatic API key rotation after usage limits",
1022
1026
  currentValue: config.autoManageSubscriptions ? "on" : "off",
1023
1027
  values: ["on", "off"],
1024
1028
  },
@@ -1029,7 +1033,7 @@ export class SettingsSelectorComponent extends Container {
1029
1033
  items.push({
1030
1034
  id: "subscriptions",
1031
1035
  label: "Subscriptions",
1032
- description: "Per-provider API key pools: set the active key, rename, clear exhaustion, remove.",
1036
+ description: "Saved API key management",
1033
1037
  currentValue: config.subscriptionCount === 0
1034
1038
  ? "none"
1035
1039
  : `${config.subscriptionCount} key${config.subscriptionCount === 1 ? "" : "s"}`,
@@ -1042,14 +1046,14 @@ export class SettingsSelectorComponent extends Container {
1042
1046
  items.splice(1, 0, {
1043
1047
  id: "show-images",
1044
1048
  label: "Show images",
1045
- description: "Render images inline in terminal",
1049
+ description: "Inline terminal image rendering",
1046
1050
  currentValue: config.showImages ? "true" : "false",
1047
1051
  values: ["true", "false"],
1048
1052
  });
1049
1053
  items.splice(2, 0, {
1050
1054
  id: "image-width-cells",
1051
1055
  label: "Image width",
1052
- description: "Preferred inline image width in terminal cells",
1056
+ description: "Inline image width in terminal cells",
1053
1057
  currentValue: String(config.imageWidthCells),
1054
1058
  values: ["60", "80", "120"],
1055
1059
  });
@@ -1058,7 +1062,7 @@ export class SettingsSelectorComponent extends Container {
1058
1062
  items.splice(supportsImages ? 3 : 1, 0, {
1059
1063
  id: "auto-resize-images",
1060
1064
  label: "Auto-resize images",
1061
- description: "Resize large images to 2000x2000 max for better model compatibility",
1065
+ description: "Limit images to 2000 x 2000 pixels",
1062
1066
  currentValue: config.autoResizeImages ? "true" : "false",
1063
1067
  values: ["true", "false"],
1064
1068
  });
@@ -1067,7 +1071,7 @@ export class SettingsSelectorComponent extends Container {
1067
1071
  items.splice(autoResizeIndex + 1, 0, {
1068
1072
  id: "block-images",
1069
1073
  label: "Block images",
1070
- description: "Prevent images from being sent to LLM providers",
1074
+ description: "Prevent images from reaching model providers",
1071
1075
  currentValue: config.blockImages ? "true" : "false",
1072
1076
  values: ["true", "false"],
1073
1077
  });
@@ -1076,16 +1080,25 @@ export class SettingsSelectorComponent extends Container {
1076
1080
  items.splice(blockImagesIndex + 1, 0, {
1077
1081
  id: "skill-commands",
1078
1082
  label: "Skill commands",
1079
- description: "Register skills as /skill:name commands",
1083
+ description: "Skills as /skill:name commands",
1080
1084
  currentValue: config.enableSkillCommands ? "true" : "false",
1081
1085
  values: ["true", "false"],
1082
1086
  });
1083
- // Hardware cursor toggle (insert after skill-commands)
1087
+ // Skill tag character (insert after skill-commands)
1084
1088
  const skillCommandsIndex = items.findIndex((item) => item.id === "skill-commands");
1085
1089
  items.splice(skillCommandsIndex + 1, 0, {
1090
+ id: "skill-tag-character",
1091
+ label: "Skill tag",
1092
+ description: "After a space, this character lists skills to tag in the message",
1093
+ currentValue: config.skillTagCharacter,
1094
+ values: [...SKILL_TAG_CHARACTERS],
1095
+ });
1096
+ // Hardware cursor toggle (insert after skill-tag-character)
1097
+ const skillTagIndex = items.findIndex((item) => item.id === "skill-tag-character");
1098
+ items.splice(skillTagIndex + 1, 0, {
1086
1099
  id: "show-hardware-cursor",
1087
1100
  label: "Show hardware cursor",
1088
- description: "Show the terminal cursor while still positioning it for IME support",
1101
+ description: "Terminal cursor for input method editors",
1089
1102
  currentValue: config.showHardwareCursor ? "true" : "false",
1090
1103
  values: ["true", "false"],
1091
1104
  });
@@ -1094,7 +1107,7 @@ export class SettingsSelectorComponent extends Container {
1094
1107
  items.splice(hardwareCursorIndex + 1, 0, {
1095
1108
  id: "editor-padding",
1096
1109
  label: "Editor padding",
1097
- description: "Horizontal padding for input editor (0-3)",
1110
+ description: "Horizontal editor padding",
1098
1111
  currentValue: String(config.editorPaddingX),
1099
1112
  values: ["0", "1", "2", "3"],
1100
1113
  });
@@ -1103,7 +1116,7 @@ export class SettingsSelectorComponent extends Container {
1103
1116
  items.splice(editorPaddingIndex + 1, 0, {
1104
1117
  id: "output-padding",
1105
1118
  label: "Output padding",
1106
- description: "Horizontal padding for user messages, assistant messages, and thinking",
1119
+ description: "Horizontal message padding",
1107
1120
  currentValue: String(config.outputPad),
1108
1121
  values: ["0", "1"],
1109
1122
  });
@@ -1112,7 +1125,7 @@ export class SettingsSelectorComponent extends Container {
1112
1125
  items.splice(outputPaddingIndex + 1, 0, {
1113
1126
  id: "autocomplete-max-visible",
1114
1127
  label: "Autocomplete max items",
1115
- description: "Max visible items in autocomplete dropdown (3-20)",
1128
+ description: "Visible autocomplete items",
1116
1129
  currentValue: String(config.autocompleteMaxVisible),
1117
1130
  values: ["3", "5", "7", "10", "15", "20"],
1118
1131
  });
@@ -1121,7 +1134,7 @@ export class SettingsSelectorComponent extends Container {
1121
1134
  items.splice(autocompleteIndex + 1, 0, {
1122
1135
  id: "clear-on-shrink",
1123
1136
  label: "Clear on shrink",
1124
- description: "Clear empty rows when content shrinks (may cause flicker)",
1137
+ description: "Clear leftover terminal rows when content shrinks",
1125
1138
  currentValue: config.clearOnShrink ? "true" : "false",
1126
1139
  values: ["true", "false"],
1127
1140
  });
@@ -1130,7 +1143,7 @@ export class SettingsSelectorComponent extends Container {
1130
1143
  items.splice(clearOnShrinkIndex + 1, 0, {
1131
1144
  id: "terminal-progress",
1132
1145
  label: "Terminal progress",
1133
- description: "Show OSC 9;4 progress indicators in the terminal tab bar",
1146
+ description: "Progress in supported terminal tabs",
1134
1147
  currentValue: config.showTerminalProgress ? "true" : "false",
1135
1148
  values: ["true", "false"],
1136
1149
  });
@@ -1156,6 +1169,9 @@ export class SettingsSelectorComponent extends Container {
1156
1169
  case "skill-commands":
1157
1170
  callbacks.onEnableSkillCommandsChange(newValue === "true");
1158
1171
  break;
1172
+ case "skill-tag-character":
1173
+ callbacks.onSkillTagCharacterChange(newValue);
1174
+ break;
1159
1175
  case "steering-mode":
1160
1176
  callbacks.onSteeringModeChange(newValue);
1161
1177
  break;