@mrclrchtr/supi-context 2.6.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  # @mrclrchtr/supi-context
10
10
 
11
- Adds a `/supi-context` command to the [pi coding agent](https://github.com/earendil-works/pi) so you can inspect how the current session is spending its context window.
11
+ Adds context-capacity observability to the [pi coding agent](https://github.com/earendil-works/pi).
12
12
 
13
13
  ## Install
14
14
 
@@ -22,56 +22,58 @@ For local development:
22
22
  pi install ./packages/supi-context
23
23
  ```
24
24
 
25
- ![Context usage report](https://raw.githubusercontent.com/mrclrchtr/supi/main/screenshots/supi-context.png)
25
+ ## Two concepts, two surfaces
26
26
 
27
- ## What you get
27
+ - A **Context Pressure Snapshot** is a small point-in-time capacity reading for deciding whether a session has room for another operation.
28
+ - A **Context Usage Report** is a diagnostic account of where the session's context is spent.
28
29
 
29
- After install, pi gets one user command and an optional agent-callable tool:
30
+ ### Human: Context Usage Report
30
31
 
31
- - `/supi-context` render a detailed context-usage report for the current session
32
- - `/supi-context full` — render the same report with the full guideline and tool-definition lists instead of previews
33
- - `supi_context` — agent-callable tool (disabled by default; see Configuration)
32
+ In interactive TUI mode, pi gets these commands:
34
33
 
35
- The command sends a custom `supi-context` message, and this package registers a dedicated renderer so the report shows up as a structured TUI view instead of plain text.
34
+ - `/supi-context` render a report with guideline and tool previews
35
+ - `/supi-context full` — render the same report with complete guideline and tool lists
36
36
 
37
- The `supi_context` tool returns the same analysis as JSON, so the agent can inspect context usage programmatically useful for checking remaining capacity before large operations or after heavy tool results. In the TUI, the tool renders a compact usage summary by default and expands into the same structured report as `/supi-context`.
37
+ The command appends a durable `supi-context` custom entry and uses a dedicated entry renderer. The report remains in the transcript but never enters LLM context.
38
+
39
+ ### Agent: Context Pressure Snapshot
40
+
41
+ `supi_context` is agent-callable when enabled in configuration. It defaults to a one-line, constant-shape JSON **Context Pressure Snapshot**:
42
+
43
+ ```ts
44
+ interface ContextPressureSnapshot {
45
+ modelName: string;
46
+ contextWindow: number | null;
47
+ usedTokens: number;
48
+ usagePercent: number | null;
49
+ compactionEnabled: boolean;
50
+ reserveTokens: number;
51
+ headroomTokens: number | null;
52
+ pressurePercent: number | null;
53
+ compacted: boolean;
54
+ approximationNote: string | null;
55
+ }
56
+ ```
57
+
58
+ Use `supi_context({ mode: "full" })` only when diagnostic attribution is needed. Full mode returns compact JSON for the Context Usage Report. If it exceeds Pi's normal tool-output limits, it returns a small valid-JSON envelope with the path to a temporary file containing the complete report.
59
+
60
+ The tool TUI never shows raw agent JSON: concise results render as a dense snapshot that expands into its metrics; full results expand into the diagnostic report.
38
61
 
39
62
  ## What the report shows
40
63
 
41
- The report is meant to answer questions like:
42
-
43
- - what is taking up space in the current context window?
44
- - how much room is left before compaction pressure gets worse?
45
- - which instruction files, context files, skills, guidelines, or tools are expensive?
46
- - what extra context was injected by other SuPi extensions?
47
-
48
- It includes:
49
-
50
- - model name, context-window size, and total token usage
51
- - approximation or pending-usage notes when exact usage data is not available yet
52
- - a visual usage bar for system prompt, user messages, assistant messages, tool calls, tool results, other, autocompact buffer, and free space
53
- - a category breakdown table for the same usage buckets
54
- - a system-prompt composition breakdown for:
55
- - base prompt content
56
- - instruction files (`AGENTS.md`, `CLAUDE.md`, etc.)
57
- - other context files loaded into the system prompt
58
- - active skills
59
- - guidelines
60
- - tool snippets
61
- - append text
62
- - instruction-file details with token cost, line count, and detected origin (`project` vs `global`)
63
- - legacy injected subdirectory context files from older `supi-claude-md` sessions, when present
64
- - active skill names with per-skill token counts
65
- - guideline bullet previews, plus source attribution for PI defaults, known built-in tools (`read`, `write`, `edit`), and `other`
66
- - active tool definitions with per-tool definition token counts and snippet-token columns when available
67
- - a compaction note when older turns were summarized
68
- - extra provider sections from extensions registered through the shared context-provider registry in `@mrclrchtr/supi-core`
64
+ The Context Usage Report includes:
65
+
66
+ - model name, context-window size, used tokens, usage percentage, pressure percentage, and **Headroom**
67
+ - the effective **Compaction reserve** and factual presence of compaction on the active branch
68
+ - approximation or pending-usage notes when exact usage is not available
69
+ - a visual usage bar and attribution-category breakdown for system prompt, messages, tool calls, tool results, and other context
70
+ - system-prompt composition, instruction/context files, skills, guideline sources, tool definitions, injected files, and registered provider sections
69
71
 
70
72
  ## Configuration
71
73
 
72
- No settings are required for the `/supi-context` command.
74
+ The human `/supi-context` command needs no configuration.
73
75
 
74
- To enable the `supi_context` agent tool, set `agentToolEnabled` to `true` in your supi config:
76
+ To enable the agent-callable `supi_context` tool, set `agentToolEnabled` to `true` in your supi config:
75
77
 
76
78
  ```json
77
79
  {
@@ -87,26 +89,18 @@ The tool is disabled by default and requires a `/reload` or restart after toggli
87
89
 
88
90
  ## Notes
89
91
 
90
- - The command uses the latest cached `systemPromptOptions` captured during `before_agent_start`.
91
- - If those prompt options are missing or incomplete, the package backfills context files and skills by re-parsing the current system prompt.
92
- - Exact totals come from pi's current context-usage data when available. Otherwise the report falls back to rough estimates and/or scales estimated category totals to the latest measured total.
93
- - If no model is selected yet, the report can still render, but the context-window bar cannot show capacity.
92
+ - The extension caches the latest `systemPromptOptions` from `before_agent_start`. If those are missing or incomplete, it backfills context files and skills from the current system prompt.
93
+ - Exact usage comes from Pi's current context-usage data when available. Otherwise the extension estimates usage and preserves an approximation note.
94
+ - The Active Context Limit is the auto-compaction threshold while auto-compaction is enabled, otherwise the raw model context window. Headroom and pressure use that limit.
94
95
 
95
96
  ## Source
96
97
 
97
- - `src/context.ts` — command registration, agent tool registration, cached prompt-option handling, and renderer wiring
98
- - `src/config.ts` — config loading with `agentToolEnabled` toggle
99
- - `src/settings-registration.ts` — `/supi-settings` registration for the agent tool toggle
100
- - `src/analysis.ts` — token accounting, attribution, and report data assembly
101
- - `src/format.ts` report orchestration for the TUI view
102
- - `src/format-helpers.ts` — shared numeric and category helpers for report rendering
103
- - `src/format-summary.ts` — summary, usage bar, category, and composition sections
104
- - `src/format-sections.ts` — instruction file, context file, skill, guideline, tool, compaction, and provider sections
105
- - `src/prompt-inference.ts` — fallback recovery of context files, skills, and guideline sections from the live system prompt
106
- - `src/renderer.ts` — custom renderer for `supi-context` messages
107
- - `src/report-component.ts` — shared width-aware report component for message and tool renderers
108
- - `src/tool/guidance.ts` — tool description, prompt snippet, and guidelines for the agent tool
109
- - `src/tool/render.ts` — TUI call/result renderer for the agent tool
110
- - `src/utils.ts` — token and plural-format helpers
98
+ - `src/context.ts` — surface registration and cached prompt-option handling
99
+ - `src/capacity.ts` — shared capacity analysis and snapshot shape
100
+ - `src/analysis.ts` — diagnostic attribution and report data assembly
101
+ - `src/entry-renderer.ts` — TUI-only custom-entry renderer for the human command
102
+ - `src/format*.ts` and `src/report-component.ts` Context Usage Report rendering
103
+ - `src/snapshot-component.ts` — compact, width-safe snapshot rendering
104
+ - `src/tool/guidance.ts`, `src/tool/output.ts`, and `src/tool/render.ts` agent-tool guidance, safe full JSON output, and tool rendering
111
105
 
112
106
  Tests live under `__tests__/unit/`.
@@ -43,7 +43,7 @@ Config file locations:
43
43
  - `registerSettingsCommand(pi)` — register `/supi-settings` (used by `@mrclrchtr/supi-settings`)
44
44
  - `openSettingsOverlay(pi, ctx)` — open the shared settings UI directly
45
45
  - `createInputSubmenu()` — helper for simple text-entry submenus
46
- - `createModelPickerSubmenu()` — helper for scoped model selection submenus
46
+ - `createModelPickerSubmenu()` — helper for scoped model selection submenus, with optional host-owned choices and `disabled` control
47
47
 
48
48
  The built-in settings UI supports:
49
49
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "2.6.1",
3
+ "version": "2.8.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -324,6 +324,7 @@ export class ScopedSettingsList {
324
324
  this.tui.requestRender();
325
325
  },
326
326
  this.ctx,
327
+ row.field.field,
327
328
  ),
328
329
  onDone: () => {
329
330
  this.submenu = null;
@@ -91,9 +91,23 @@ export interface StringListField extends BaseField {
91
91
  kind: "stringList";
92
92
  }
93
93
 
94
+ /** One non-model choice shown before the scoped models in a model picker. */
95
+ export interface ModelPickerStaticOption {
96
+ /** Persisted value for the choice. */
97
+ value: string;
98
+ /** Human-readable picker label. */
99
+ label: string;
100
+ /** Optional explanation shown alongside the label. */
101
+ description?: string;
102
+ }
103
+
94
104
  /** Model picker backed by the scoped model set. */
95
105
  export interface ModelPickerField extends BaseField {
96
106
  kind: "modelPicker";
107
+ /** Additional host-owned choices shown before scoped models. */
108
+ staticOptions?: ModelPickerStaticOption[];
109
+ /** Whether to include the built-in `disabled` choice. Defaults to true. */
110
+ includeDisabled?: boolean;
97
111
  }
98
112
 
99
113
  /**
@@ -14,6 +14,7 @@ import {
14
14
  Text,
15
15
  } from "@earendil-works/pi-tui";
16
16
  import { getSelectableModels } from "../model-selection.ts";
17
+ import type { ModelPickerField } from "./settings-schema.ts";
17
18
 
18
19
  /**
19
20
  * Creates a pi-tui Input-backed submenu component with enter-to-confirm
@@ -57,25 +58,26 @@ export function createInputSubmenu(
57
58
  }
58
59
 
59
60
  /**
60
- * Creates a model picker submenu for settings with "disabled" as the first option.
61
+ * Creates a model picker submenu backed by the scoped model set.
62
+ *
63
+ * The built-in `disabled` choice remains enabled by default. Callers can add
64
+ * host-owned static choices or omit `disabled` through the field options.
61
65
  */
62
66
  export function createModelPickerSubmenu(
63
67
  currentValue: string,
64
68
  done: (selectedValue?: string) => void,
65
69
  ctx?: ExtensionContext,
70
+ options: Pick<ModelPickerField, "includeDisabled" | "staticOptions"> = {},
66
71
  ): {
67
72
  render: (width: number) => string[];
68
73
  invalidate: () => void;
69
74
  handleInput: (data: string) => boolean;
70
75
  } {
71
- const items = buildModelItems(ctx);
72
- const initialIndex =
73
- currentValue === "disabled"
74
- ? 0
75
- : Math.max(
76
- 0,
77
- items.findIndex((item) => item.value === currentValue),
78
- );
76
+ const items = buildModelItems(ctx, options);
77
+ const initialIndex = Math.max(
78
+ 0,
79
+ items.findIndex((item) => item.value === currentValue),
80
+ );
79
81
 
80
82
  const container = new Container();
81
83
  container.addChild(new Text(" Select model", 1, 0));
@@ -105,20 +107,35 @@ export function createModelPickerSubmenu(
105
107
  };
106
108
  }
107
109
 
108
- /** Build selectable model items with "disabled" as the first option. */
109
- function buildModelItems(ctx?: ExtensionContext): SelectItem[] {
110
- const items: SelectItem[] = [
111
- { value: "disabled", label: "disabled", description: "No model selected" },
112
- ];
110
+ /** Build static choices followed by the selectable scoped models. */
111
+ function buildModelItems(
112
+ ctx: ExtensionContext | undefined,
113
+ options: Pick<ModelPickerField, "includeDisabled" | "staticOptions">,
114
+ ): SelectItem[] {
115
+ const items: SelectItem[] = [];
116
+ const seen = new Set<string>();
117
+ for (const option of options.staticOptions ?? []) {
118
+ if (seen.has(option.value)) continue;
119
+ items.push({ ...option });
120
+ seen.add(option.value);
121
+ }
122
+
123
+ if (options.includeDisabled !== false && !seen.has("disabled")) {
124
+ items.push({ value: "disabled", label: "disabled", description: "No model selected" });
125
+ seen.add("disabled");
126
+ }
127
+
113
128
  if (!ctx) return items;
114
129
  const models = getSelectableModels(ctx);
115
130
  for (const model of models) {
131
+ if (seen.has(model.canonicalId)) continue;
116
132
  const suffix = model.isCurrent ? " [current]" : "";
117
133
  items.push({
118
134
  value: model.canonicalId,
119
135
  label: `${model.canonicalId}${suffix}`,
120
136
  description: model.label !== model.canonicalId ? model.label : undefined,
121
137
  });
138
+ seen.add(model.canonicalId);
122
139
  }
123
140
  return items;
124
141
  }
@@ -20,6 +20,7 @@ export type {
20
20
  DeclarativeSettingsOptions,
21
21
  EnumField,
22
22
  ModelPickerField,
23
+ ModelPickerStaticOption,
23
24
  NumberField,
24
25
  ScopedFieldValue,
25
26
  SettingsField,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-context",
3
- "version": "2.6.1",
4
- "description": "SuPi Context extension — detailed context usage report via /supi-context command",
3
+ "version": "2.8.0",
4
+ "description": "SuPi Context extension — agent pressure snapshots and TUI usage reports",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -32,16 +32,20 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "typebox": "*",
35
- "@mrclrchtr/supi-core": "2.6.1"
35
+ "@mrclrchtr/supi-core": "2.8.0"
36
36
  },
37
37
  "bundledDependencies": [
38
38
  "@mrclrchtr/supi-core"
39
39
  ],
40
40
  "peerDependencies": {
41
+ "@earendil-works/pi-ai": "*",
41
42
  "@earendil-works/pi-coding-agent": "*",
42
43
  "@earendil-works/pi-tui": "*"
43
44
  },
44
45
  "peerDependenciesMeta": {
46
+ "@earendil-works/pi-ai": {
47
+ "optional": true
48
+ },
45
49
  "@earendil-works/pi-coding-agent": {
46
50
  "optional": true
47
51
  },
@@ -52,8 +56,7 @@
52
56
  "pi": {
53
57
  "extensions": [
54
58
  "./src/extension.ts"
55
- ],
56
- "image": "https://raw.githubusercontent.com/mrclrchtr/supi/main/screenshots/supi-context.png"
59
+ ]
57
60
  },
58
61
  "main": "src/api.ts",
59
62
  "exports": {