@oh-my-pi/pi-coding-agent 15.11.4 → 15.11.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 (98) hide show
  1. package/CHANGELOG.md +82 -1
  2. package/dist/cli.js +520 -451
  3. package/dist/types/cli/bench-cli.d.ts +78 -0
  4. package/dist/types/cli/usage-cli.d.ts +10 -1
  5. package/dist/types/commands/bench.d.ts +29 -0
  6. package/dist/types/commands/usage.d.ts +9 -0
  7. package/dist/types/config/model-resolver.d.ts +3 -2
  8. package/dist/types/config/settings-schema.d.ts +125 -3
  9. package/dist/types/edit/renderer.d.ts +1 -0
  10. package/dist/types/modes/components/oauth-selector.d.ts +10 -1
  11. package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
  12. package/dist/types/modes/components/session-selector.d.ts +1 -1
  13. package/dist/types/modes/components/settings-selector.d.ts +8 -1
  14. package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
  15. package/dist/types/modes/components/tool-execution.d.ts +18 -0
  16. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  17. package/dist/types/modes/interactive-mode.d.ts +10 -0
  18. package/dist/types/modes/session-observer-registry.d.ts +2 -0
  19. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +3 -0
  20. package/dist/types/modes/setup-wizard/scenes/types.d.ts +10 -1
  21. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +3 -0
  22. package/dist/types/modes/types.d.ts +2 -0
  23. package/dist/types/modes/utils/context-usage.d.ts +6 -1
  24. package/dist/types/session/agent-session.d.ts +14 -1
  25. package/dist/types/session/auth-storage.d.ts +1 -1
  26. package/dist/types/session/codex-auto-reset.d.ts +107 -0
  27. package/dist/types/session/snapcompact-inline.d.ts +107 -4
  28. package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
  29. package/dist/types/task/render.d.ts +1 -0
  30. package/dist/types/tools/bash.d.ts +2 -0
  31. package/dist/types/tools/eval-render.d.ts +1 -0
  32. package/dist/types/tools/renderers.d.ts +13 -0
  33. package/dist/types/tools/ssh.d.ts +1 -0
  34. package/dist/types/tools/todo.d.ts +0 -11
  35. package/package.json +11 -11
  36. package/src/cli/bench-cli.ts +437 -0
  37. package/src/cli/usage-cli.ts +187 -16
  38. package/src/cli-commands.ts +1 -0
  39. package/src/commands/bench.ts +42 -0
  40. package/src/commands/usage.ts +8 -0
  41. package/src/config/model-registry.ts +52 -5
  42. package/src/config/model-resolver.ts +36 -5
  43. package/src/config/settings-schema.ts +148 -3
  44. package/src/config/settings.ts +9 -0
  45. package/src/edit/renderer.ts +5 -0
  46. package/src/hindsight/client.ts +26 -1
  47. package/src/hindsight/state.ts +6 -2
  48. package/src/internal-urls/docs-index.generated.ts +2 -2
  49. package/src/mcp/transports/stdio.ts +81 -7
  50. package/src/modes/components/oauth-selector.ts +67 -7
  51. package/src/modes/components/reset-usage-selector.ts +161 -0
  52. package/src/modes/components/session-selector.ts +8 -2
  53. package/src/modes/components/settings-selector.ts +89 -47
  54. package/src/modes/components/snapcompact-shape-preview-doc.md +11 -0
  55. package/src/modes/components/snapcompact-shape-preview.ts +192 -0
  56. package/src/modes/components/tool-execution.ts +26 -0
  57. package/src/modes/components/transcript-container.ts +23 -1
  58. package/src/modes/controllers/command-controller.ts +24 -1
  59. package/src/modes/controllers/input-controller.ts +8 -6
  60. package/src/modes/controllers/selector-controller.ts +72 -2
  61. package/src/modes/interactive-mode.ts +83 -0
  62. package/src/modes/session-observer-registry.ts +61 -3
  63. package/src/modes/setup-wizard/index.ts +1 -0
  64. package/src/modes/setup-wizard/scenes/glyph.ts +24 -6
  65. package/src/modes/setup-wizard/scenes/providers.ts +36 -2
  66. package/src/modes/setup-wizard/scenes/sign-in.ts +10 -1
  67. package/src/modes/setup-wizard/scenes/theme.ts +28 -1
  68. package/src/modes/setup-wizard/scenes/types.ts +10 -1
  69. package/src/modes/setup-wizard/scenes/web-search.ts +22 -6
  70. package/src/modes/setup-wizard/wizard-overlay.ts +38 -1
  71. package/src/modes/theme/theme.ts +2 -2
  72. package/src/modes/types.ts +2 -0
  73. package/src/modes/utils/context-usage.ts +75 -1
  74. package/src/prompts/bench.md +7 -0
  75. package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
  76. package/src/prompts/system/snapcompact-context-stub.md +1 -0
  77. package/src/prompts/system/snapcompact-toolresult-note.md +1 -1
  78. package/src/prompts/tools/browser.md +33 -43
  79. package/src/prompts/tools/eval.md +27 -50
  80. package/src/prompts/tools/irc.md +29 -31
  81. package/src/prompts/tools/read.md +31 -37
  82. package/src/prompts/tools/todo.md +1 -2
  83. package/src/sdk.ts +4 -2
  84. package/src/session/agent-session.ts +136 -6
  85. package/src/session/auth-storage.ts +3 -0
  86. package/src/session/codex-auto-reset.ts +190 -0
  87. package/src/session/snapcompact-inline.ts +404 -75
  88. package/src/slash-commands/builtin-registry.ts +145 -8
  89. package/src/slash-commands/helpers/context-report.ts +28 -1
  90. package/src/slash-commands/helpers/reset-usage.ts +66 -0
  91. package/src/slash-commands/helpers/usage-report.ts +12 -0
  92. package/src/task/index.ts +30 -7
  93. package/src/task/render.ts +34 -19
  94. package/src/tools/bash.ts +3 -0
  95. package/src/tools/eval-render.ts +4 -0
  96. package/src/tools/renderers.ts +13 -0
  97. package/src/tools/ssh.ts +3 -0
  98. package/src/tools/todo.ts +8 -128
@@ -0,0 +1,78 @@
1
+ import type { ResolvedThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
+ import type { Api, ApiKeyResolver, AssistantMessageEventStream, Context, Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
3
+ import type { CanonicalModelVariant } from "@oh-my-pi/pi-catalog/identity";
4
+ import type { ApiKeyResolverModel } from "../config/api-key-resolver";
5
+ import { type CanonicalModelQueryOptions } from "../config/model-registry";
6
+ import { Settings } from "../config/settings";
7
+ export interface BenchCommandArgs {
8
+ models: string[];
9
+ flags: {
10
+ runs?: number;
11
+ maxTokens?: number;
12
+ prompt?: string;
13
+ json?: boolean;
14
+ };
15
+ }
16
+ export interface BenchModelRegistry {
17
+ getAll(): Model<Api>[];
18
+ getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined>;
19
+ resolver(model: ApiKeyResolverModel, sessionId?: string): ApiKeyResolver;
20
+ resolveCanonicalModel?(canonicalId: string, options?: CanonicalModelQueryOptions): Model<Api> | undefined;
21
+ getCanonicalVariants?(canonicalId: string, options?: CanonicalModelQueryOptions): CanonicalModelVariant[];
22
+ getCanonicalId?(model: Model<Api>): string | undefined;
23
+ }
24
+ export interface BenchRuntime {
25
+ modelRegistry: BenchModelRegistry;
26
+ settings?: Settings;
27
+ close?: () => void;
28
+ }
29
+ export interface BenchRunSuccess {
30
+ ok: true;
31
+ ttftMs: number;
32
+ durationMs: number;
33
+ outputTokens: number;
34
+ /** Generation throughput measured over the post-first-token window. */
35
+ tokensPerSecond: number;
36
+ }
37
+ export interface BenchRunFailure {
38
+ ok: false;
39
+ error: string;
40
+ }
41
+ export type BenchRunResult = BenchRunSuccess | BenchRunFailure;
42
+ export interface BenchAverages {
43
+ ttftMs: number;
44
+ durationMs: number;
45
+ outputTokens: number;
46
+ tokensPerSecond: number;
47
+ }
48
+ export interface BenchModelReport {
49
+ /** Selector as the user typed it (e.g. "opus" or "gemini-3.5:low"). */
50
+ selector: string;
51
+ /** Resolved `provider/id`. */
52
+ model: string;
53
+ /** Explicit thinking level from a `:level` selector suffix; undefined = provider default. */
54
+ thinking?: ResolvedThinkingLevel;
55
+ results: BenchRunResult[];
56
+ /** Averages over successful runs; null when every run failed. */
57
+ average: BenchAverages | null;
58
+ }
59
+ export interface BenchSummary {
60
+ runs: number;
61
+ maxTokens: number;
62
+ models: BenchModelReport[];
63
+ failures: number;
64
+ }
65
+ type BenchStreamSimple = (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
66
+ export interface BenchDependencies {
67
+ createRuntime?: () => Promise<BenchRuntime>;
68
+ randomSessionId?: () => string;
69
+ writeStdout?: (text: string) => void;
70
+ writeStderr?: (text: string) => void;
71
+ setExitCode?: (code: number) => void;
72
+ streamSimple?: BenchStreamSimple;
73
+ now?: () => number;
74
+ stdoutIsTTY?: boolean;
75
+ }
76
+ export declare function formatBenchTable(summary: BenchSummary): string;
77
+ export declare function runBenchCommand(command: BenchCommandArgs, deps?: BenchDependencies): Promise<BenchSummary>;
78
+ export {};
@@ -7,11 +7,15 @@
7
7
  * credentials produced no usage report are listed too, so the output
8
8
  * always covers the full credential pool.
9
9
  */
10
- import type { UsageReport } from "@oh-my-pi/pi-ai";
10
+ import { type UsageHistoryEntry, type UsageReport } from "@oh-my-pi/pi-ai";
11
11
  export interface UsageCommandArgs {
12
12
  json?: boolean;
13
13
  provider?: string;
14
14
  redact?: boolean;
15
+ /** Show recorded usage-limit history instead of a live snapshot. */
16
+ history?: boolean;
17
+ /** History window in days (with `history`). */
18
+ days?: number;
15
19
  }
16
20
  /** Identity slice of a stored credential, for "every account" coverage. */
17
21
  export interface UsageAccountIdentity {
@@ -69,4 +73,9 @@ export declare function computeProviderWindowStats(reports: UsageReport[]): Prov
69
73
  * each provider section as "no usage data" rows.
70
74
  */
71
75
  export declare function formatUsageBreakdown(reports: UsageReport[], accounts: UsageAccountIdentity[], nowMs: number, redaction?: Map<string, string>): string;
76
+ /**
77
+ * Render recorded usage-limit history: per provider, per account, one
78
+ * peak-per-bucket sparkline per limit window plus latest/peak percentages.
79
+ */
80
+ export declare function formatUsageHistory(entries: UsageHistoryEntry[], sinceMs: number, nowMs: number, redaction?: Map<string, string>): string;
72
81
  export declare function runUsageCommand(cmd: UsageCommandArgs): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { Command } from "@oh-my-pi/pi-utils/cli";
2
+ export default class Bench extends Command {
3
+ static description: string;
4
+ static args: {
5
+ models: import("@oh-my-pi/pi-utils/cli").ArgDescriptor & {
6
+ description: string;
7
+ required: true;
8
+ multiple: true;
9
+ };
10
+ };
11
+ static flags: {
12
+ runs: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
13
+ description: string;
14
+ default: number;
15
+ };
16
+ "max-tokens": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
17
+ description: string;
18
+ default: number;
19
+ };
20
+ prompt: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
21
+ description: string;
22
+ };
23
+ json: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
24
+ description: string;
25
+ };
26
+ };
27
+ static examples: string[];
28
+ run(): Promise<void>;
29
+ }
@@ -19,6 +19,15 @@ export default class Usage extends Command {
19
19
  description: string;
20
20
  default: boolean;
21
21
  };
22
+ history: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
23
+ description: string;
24
+ default: boolean;
25
+ };
26
+ days: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
27
+ char: string;
28
+ description: string;
29
+ default: number;
30
+ };
22
31
  };
23
32
  static examples: string[];
24
33
  run(): Promise<void>;
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Layering:
5
5
  * - `matchModel` is the single matching engine. Order: exact `provider/id`
6
- * reference (with OpenRouter routed/date fallbacks) → exact canonical id →
7
- * exact bare id → provider-scoped fuzzysubstring with alias-vs-dated pick.
6
+ * reference (with variant-alias and OpenRouter routed/date fallbacks) →
7
+ * exact canonical id → exact bare id retired variant alias
8
+ * provider-scoped fuzzy → substring with alias-vs-dated pick.
8
9
  * - `parseModelPatternWithContext`/`parseModelPattern` layer the selector
9
10
  * grammar on top: trailing `:level` thinking suffixes (`splitThinkingSuffix`)
10
11
  * and `@upstream` provider routing (`splitUpstreamRouting`).
@@ -1738,13 +1738,27 @@ export declare const SETTINGS_SCHEMA: {
1738
1738
  };
1739
1739
  };
1740
1740
  readonly "snapcompact.systemPrompt": {
1741
- readonly type: "boolean";
1742
- readonly default: false;
1741
+ readonly type: "enum";
1742
+ readonly values: readonly ["none", "agents-md", "all"];
1743
+ readonly default: "none";
1743
1744
  readonly ui: {
1744
1745
  readonly tab: "context";
1745
1746
  readonly group: "Experimental";
1746
1747
  readonly label: "Snapcompact System Prompt";
1747
- readonly description: "Experimental: render the system prompt as dense PNG image(s) and attach to the first user message (vision models only). Saves tokens; loses system-prompt prompt caching.";
1748
+ readonly description: "Experimental: render selected system prompt text as dense PNG image(s) and attach to the first user message (vision models only). Saves tokens; loses prompt caching for imaged text.";
1749
+ readonly options: readonly [{
1750
+ readonly value: "none";
1751
+ readonly label: "None";
1752
+ readonly description: "Keep the system prompt as text.";
1753
+ }, {
1754
+ readonly value: "agents-md";
1755
+ readonly label: "AGENTS.md";
1756
+ readonly description: "Only move loaded context-file instructions to images, when that saves tokens.";
1757
+ }, {
1758
+ readonly value: "all";
1759
+ readonly label: "All";
1760
+ readonly description: "Move the full system prompt to images, when that saves tokens.";
1761
+ }];
1748
1762
  };
1749
1763
  };
1750
1764
  readonly "snapcompact.toolResults": {
@@ -1757,6 +1771,78 @@ export declare const SETTINGS_SCHEMA: {
1757
1771
  readonly description: "Experimental: render large historical tool results as dense PNG image(s) instead of text (vision models only). Saves tokens on accumulated read/search output.";
1758
1772
  };
1759
1773
  };
1774
+ readonly "snapcompact.shape": {
1775
+ readonly type: "enum";
1776
+ readonly values: readonly ["auto", ...("5x8-bw" | "5x8-sent" | "6x12-dim" | "6x6u-bw" | "6x6u-sent" | "8on16-bw" | "8x13-bw" | "8x8r-bw" | "8x8r-sent" | "8x8u-bw" | "8x8u-sent" | "doc-8on16-bw" | "doc-8on16-sent" | "doc-8on16-sent-dim")[]];
1777
+ readonly default: "auto";
1778
+ readonly ui: {
1779
+ readonly tab: "context";
1780
+ readonly group: "Experimental";
1781
+ readonly label: "Snapcompact Shape";
1782
+ readonly description: "Frame shape snapcompact prints text with (compaction archive and inline imaging). Auto picks a shape tuned for the current model.";
1783
+ readonly options: readonly [{
1784
+ readonly value: "auto";
1785
+ readonly label: "Auto";
1786
+ readonly description: "Picks a shape tuned for the current model, falling back to its provider family.";
1787
+ }, {
1788
+ readonly value: "8x8r-bw";
1789
+ readonly label: "8x8 repeated, black";
1790
+ readonly description: "unscii square cell, black ink, every line printed twice with the copy on a pale highlight band.";
1791
+ }, {
1792
+ readonly value: "8x8r-sent";
1793
+ readonly label: "8x8 repeated, sentence hues";
1794
+ readonly description: "Repeated grid with ink cycling six hues at sentence boundaries.";
1795
+ }, {
1796
+ readonly value: "8x8u-bw";
1797
+ readonly label: "8x8, black";
1798
+ readonly description: "Plain unscii square cell, single-printed lines, black ink.";
1799
+ }, {
1800
+ readonly value: "8x8u-sent";
1801
+ readonly label: "8x8, sentence hues";
1802
+ readonly description: "Plain unscii square cell with sentence-hue ink.";
1803
+ }, {
1804
+ readonly value: "6x6u-bw";
1805
+ readonly label: "6x6 dense, black";
1806
+ readonly description: "unscii squeezed to 6x6 — densest readable cell, fewest frames — in black ink.";
1807
+ }, {
1808
+ readonly value: "6x6u-sent";
1809
+ readonly label: "6x6 dense, sentence hues";
1810
+ readonly description: "Densest cell with sentence-hue ink.";
1811
+ }, {
1812
+ readonly value: "5x8-bw";
1813
+ readonly label: "5x8 legacy, black";
1814
+ readonly description: "Original X.org 5x8 glyphs on the 2576px frame, black ink.";
1815
+ }, {
1816
+ readonly value: "5x8-sent";
1817
+ readonly label: "5x8 legacy, sentence hues";
1818
+ readonly description: "The original snapcompact shape (pre-shape-table sessions rendered this).";
1819
+ }, {
1820
+ readonly value: "6x12-dim";
1821
+ readonly label: "6x12, dimmed stopwords";
1822
+ readonly description: "X.org 6x12 glyphs, black ink, function words dimmed gray.";
1823
+ }, {
1824
+ readonly value: "8x13-bw";
1825
+ readonly label: "8x13, black";
1826
+ readonly description: "X.org 8x13 glyphs, black ink.";
1827
+ }, {
1828
+ readonly value: "8on16-bw";
1829
+ readonly label: "8x13 on 16px pitch, black";
1830
+ readonly description: "8x13 glyphs on an 8x16 cell (extra leading), black ink.";
1831
+ }, {
1832
+ readonly value: "doc-8on16-bw";
1833
+ readonly label: "Doc 8on16, black";
1834
+ readonly description: "Two word-wrapped newspaper columns of 8x13 glyphs on a 16px pitch, black ink.";
1835
+ }, {
1836
+ readonly value: "doc-8on16-sent";
1837
+ readonly label: "Doc 8on16, sentence hues";
1838
+ readonly description: "Two-column doc layout with sentence-hue ink.";
1839
+ }, {
1840
+ readonly value: "doc-8on16-sent-dim";
1841
+ readonly label: "Doc 8on16, sentence hues + dimmed stopwords";
1842
+ readonly description: "Two-column doc layout, sentence-hue ink, function words dimmed gray.";
1843
+ }];
1844
+ };
1845
+ };
1760
1846
  readonly "branchSummary.enabled": {
1761
1847
  readonly type: "boolean";
1762
1848
  readonly default: false;
@@ -4102,6 +4188,36 @@ export declare const SETTINGS_SCHEMA: {
4102
4188
  }];
4103
4189
  };
4104
4190
  };
4191
+ readonly "codexResets.autoRedeem": {
4192
+ readonly type: "boolean";
4193
+ readonly default: false;
4194
+ readonly ui: {
4195
+ readonly tab: "providers";
4196
+ readonly group: "Services";
4197
+ readonly label: "Codex Auto-Redeem Saved Resets";
4198
+ readonly description: "When a turn is blocked by the Codex weekly limit on the active account and no other account is available, automatically spend one saved rate-limit reset (ChatGPT 'save rate limit resets'). Conservative: never fires for 5-hour-only or Spark limits, near a natural reset, or twice for the same block. Requires retries enabled.";
4199
+ };
4200
+ };
4201
+ readonly "codexResets.minBlockedMinutes": {
4202
+ readonly type: "number";
4203
+ readonly default: 60;
4204
+ readonly ui: {
4205
+ readonly tab: "providers";
4206
+ readonly group: "Services";
4207
+ readonly label: "Codex Auto-Redeem Min Block";
4208
+ readonly description: "Only auto-redeem when the natural weekly reset is at least this many minutes away (don't spend a ~30-day credit to save a short wait).";
4209
+ };
4210
+ };
4211
+ readonly "codexResets.keepCredits": {
4212
+ readonly type: "number";
4213
+ readonly default: 0;
4214
+ readonly ui: {
4215
+ readonly tab: "providers";
4216
+ readonly group: "Services";
4217
+ readonly label: "Codex Auto-Redeem Reserve";
4218
+ readonly description: "Never auto-spend below this many saved resets (0 = the last credit may be spent automatically).";
4219
+ };
4220
+ };
4105
4221
  readonly "provider.appendOnlyContext": {
4106
4222
  readonly type: "enum";
4107
4223
  readonly values: readonly ["auto", "on", "off"];
@@ -4451,6 +4567,11 @@ export interface ShellMinimizerSettings {
4451
4567
  sourceOutlineLevel: "default" | "aggressive";
4452
4568
  legacyFilters: boolean | undefined;
4453
4569
  }
4570
+ export interface CodexResetsSettings {
4571
+ autoRedeem: boolean;
4572
+ minBlockedMinutes: number;
4573
+ keepCredits: number;
4574
+ }
4454
4575
  /** Map group prefix -> typed settings interface */
4455
4576
  export interface GroupTypeMap {
4456
4577
  compaction: CompactionSettings;
@@ -4469,6 +4590,7 @@ export interface GroupTypeMap {
4469
4590
  modelTags: ModelTagsSettings;
4470
4591
  cycleOrder: string[];
4471
4592
  shellMinimizer: ShellMinimizerSettings;
4593
+ codexResets: CodexResetsSettings;
4472
4594
  }
4473
4595
  export type GroupPrefix = keyof GroupTypeMap;
4474
4596
  export {};
@@ -93,6 +93,7 @@ export interface EditRenderContext {
93
93
  }
94
94
  export declare const editToolRenderer: {
95
95
  mergeCallAndResult: boolean;
96
+ provisionalPendingPreview: boolean;
96
97
  renderCall(args: EditRenderArgs, options: RenderResultOptions & {
97
98
  renderContext?: EditRenderContext;
98
99
  }, uiTheme: Theme): Component;
@@ -1,4 +1,4 @@
1
- import { Container } from "@oh-my-pi/pi-tui";
1
+ import { Container, type SgrMouseEvent } from "@oh-my-pi/pi-tui";
2
2
  import type { AuthStorage } from "../../session/auth-storage";
3
3
  /**
4
4
  * Component that renders an OAuth provider selector.
@@ -11,4 +11,13 @@ export declare class OAuthSelectorComponent extends Container {
11
11
  });
12
12
  stopValidation(): void;
13
13
  handleInput(keyData: string): void;
14
+ /** Move the selection one step for a wheel notch (clamped, no wrap). */
15
+ handleWheel(delta: -1 | 1): void;
16
+ /**
17
+ * Route an SGR mouse report at component-local coordinates. Provider rows
18
+ * start LIST_ROW_OFFSET lines into the render; the ScrollView window shows
19
+ * #visibleCount rows from #scrollStart. Wheel moves the selection, motion
20
+ * drives the hover band, and a left click selects and confirms like Enter.
21
+ */
22
+ routeMouse(event: SgrMouseEvent, line: number, _col: number): void;
14
23
  }
@@ -0,0 +1,12 @@
1
+ import { Container } from "@oh-my-pi/pi-tui";
2
+ import type { ResetUsageAccount } from "../../slash-commands/helpers/reset-usage";
3
+ /**
4
+ * Account picker for `/usage reset`. Lists Codex accounts with their saved
5
+ * rate-limit reset counts; selecting one redeems a reset. Because a reset is a
6
+ * scarce, irreversible credit, Enter requires a second press to confirm.
7
+ */
8
+ export declare class ResetUsageSelectorComponent extends Container {
9
+ #private;
10
+ constructor(accounts: ResetUsageAccount[], onSelect: (account: ResetUsageAccount) => void, onCancel: () => void);
11
+ handleInput(keyData: string): void;
12
+ }
@@ -8,7 +8,7 @@ export type SessionHistoryMatcher = (query: string) => string[];
8
8
  * Resume search narrows a recency-sorted list: once every query token appears
9
9
  * as a literal substring, newer sessions should beat a slightly better fuzzy
10
10
  * position match. Pure fuzzy/acronym matches still sort by fuzzy score after
11
- * literal matches.
11
+ * literal matches, but weak pure fuzzy tokens are dropped as noise.
12
12
  */
13
13
  export declare function rankSessionSearchMatches(allSessions: SessionInfo[], query: string): SessionInfo[];
14
14
  /**
@@ -1,6 +1,7 @@
1
1
  import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Effort } from "@oh-my-pi/pi-ai";
3
- import { type Component } from "@oh-my-pi/pi-tui";
3
+ import { type Component, type ImageBudget } from "@oh-my-pi/pi-tui";
4
+ import type { ShapeTarget } from "@oh-my-pi/snapcompact";
4
5
  import { type SettingPath } from "../../config/settings";
5
6
  import type { StatusLinePreset, StatusLineSegmentId, StatusLineSeparatorStyle } from "../../config/settings-schema";
6
7
  /**
@@ -16,6 +17,12 @@ export interface SettingsRuntimeContext {
16
17
  availableThemes: string[];
17
18
  /** Working directory for plugins tab */
18
19
  cwd: string;
20
+ /** Active model (api + id); resolves what the snapcompact `auto` shape maps to. */
21
+ model?: ShapeTarget;
22
+ /** Shared TUI image budget (graphics ids + transmit-once) for image previews. */
23
+ imageBudget?: ImageBudget;
24
+ /** Schedules a re-render after async preview work completes. */
25
+ requestRender?: () => void;
19
26
  }
20
27
  /** Status line settings subset for preview */
21
28
  export interface StatusLinePreviewSettings {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Live preview for the `snapcompact.shape` setting: renders a sample session
3
+ * transcript through the real snapcompact rasterizer as a miniature page and
4
+ * shows it zoomed, so cell size, ink hues, highlight bands, and dim tool-result
5
+ * spans are legible at terminal scale.
6
+ *
7
+ * The mini-frame (a {@link SRC_FRAME_PX}px page) is upscaled with
8
+ * nearest-neighbor so the glyph pixels stay crisp when the terminal scales the
9
+ * placement box. Graphics display requires the Kitty unicode-placeholder path —
10
+ * `renderImage` returning `lines` is the gate — because the bordered settings
11
+ * frame re-fits every row, which direct cursor-positioned placements (iTerm2,
12
+ * Sixel, Kitty `a=p`) do not survive. Everything else falls back to the stats
13
+ * line plus a dim notice.
14
+ */
15
+ import { type Component, type ImageBudget } from "@oh-my-pi/pi-tui";
16
+ import { type ShapeTarget } from "@oh-my-pi/snapcompact";
17
+ export interface SnapcompactShapePreviewOptions {
18
+ /** Active model (api + id); resolves what `auto` maps to for this reader. */
19
+ model?: ShapeTarget;
20
+ /** Shared TUI image budget: stable graphics ids, transmit-once, exit cleanup. */
21
+ imageBudget?: ImageBudget;
22
+ /** Schedules a re-render once an async sample render completes. */
23
+ requestRender?: () => void;
24
+ }
25
+ export declare class SnapcompactShapePreview implements Component {
26
+ #private;
27
+ constructor(currentValue: string, options?: SnapcompactShapePreviewOptions);
28
+ /** Track the highlighted option; the next render reflects it. */
29
+ setValue(value: string): void;
30
+ render(width: number): readonly string[];
31
+ }
@@ -72,6 +72,24 @@ export declare class ToolExecutionComponent extends Container {
72
72
  * past, or an explicit {@link seal} flips it to `true`.
73
73
  */
74
74
  isTranscriptBlockFinalized(): boolean;
75
+ /**
76
+ * Whether this still-live block's settled rows may enter native scrollback
77
+ * (see `FinalizableBlock.isTranscriptBlockCommitStable`). Classification is
78
+ * per renderer (`ToolRenderer.provisionalPendingPreview`): tail-window
79
+ * streaming views (edit's streamed-diff tail, bash/ssh command caps, eval
80
+ * cells) are re-anchored top-first by the result render, so promoting
81
+ * their visually static head — e.g. an edit preview idling on its last
82
+ * frame while the apply + LSP pass runs — would strand a stale copy of
83
+ * the call box above the final block the moment the result lands. Every
84
+ * other pending preview streams top-anchored append-shaped rows the
85
+ * result render preserves (a task call's context/assignment markdown, a
86
+ * write's content), so it stays commit-eligible — a call taller than the
87
+ * viewport scrolls into native history mid-stream instead of reading as
88
+ * cut off until the result. Expanded blocks always stream top-anchored
89
+ * (the over-tall write/eval scrollback contract). Displaceable waiting
90
+ * polls are removed wholesale by the next poll and must never commit.
91
+ */
92
+ isTranscriptBlockCommitStable(): boolean;
75
93
  /**
76
94
  * Mark the tool terminal even though no result arrived (the turn aborted or
77
95
  * abandoned it) and stop animating, so it can freeze and stops pinning the
@@ -41,6 +41,7 @@ export declare class SelectorController {
41
41
  handleResumeSession(sessionPath: string): Promise<void>;
42
42
  handleSessionDeleteCommand(): Promise<void>;
43
43
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
44
+ showResetUsageSelector(): Promise<void>;
44
45
  showDebugSelector(): Promise<void>;
45
46
  showAgentHub(observers: SessionObserverRegistry): void;
46
47
  }
@@ -27,6 +27,7 @@ import type { ToolExecutionHandle } from "./components/tool-execution";
27
27
  import { TranscriptContainer } from "./components/transcript-container";
28
28
  import { type LoopLimitRuntime } from "./loop-limit";
29
29
  import { OAuthManualInputManager } from "./oauth-manual-input";
30
+ import type { ObservableSession } from "./session-observer-registry";
30
31
  import type { Theme } from "./theme/theme";
31
32
  import type { CompactionQueuedMessage, InteractiveModeContext, InteractiveModeInitOptions, InteractiveSelectorDialogOptions, SubmittedUserInput, TodoItem, TodoPhase } from "./types";
32
33
  /** Options for creating an InteractiveMode instance (for future API use) */
@@ -42,6 +43,13 @@ export interface InteractiveModeOptions {
42
43
  /** Additional initial messages to queue */
43
44
  initialMessages?: string[];
44
45
  }
46
+ /**
47
+ * Build the anchored subagent HUD block: a bold accent "Subagents" header plus
48
+ * one hooked row per running agent in the same `Id: description` shape the
49
+ * inline task rows use (muted task preview when no description was given).
50
+ * Returns an empty array when nothing is running so the container can clear.
51
+ */
52
+ export declare function renderSubagentHudLines(sessions: ObservableSession[], columns: number): string[];
45
53
  export declare class InteractiveMode implements InteractiveModeContext {
46
54
  #private;
47
55
  session: AgentSession;
@@ -56,6 +64,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
56
64
  pendingMessagesContainer: Container;
57
65
  statusContainer: Container;
58
66
  todoContainer: Container;
67
+ subagentContainer: Container;
59
68
  btwContainer: Container;
60
69
  omfgContainer: Container;
61
70
  errorBannerContainer: Container;
@@ -265,6 +274,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
265
274
  handleResumeSession(sessionPath: string): Promise<void>;
266
275
  handleSessionDeleteCommand(): Promise<void>;
267
276
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
277
+ showResetUsageSelector(): Promise<void>;
268
278
  showProviderSetup(): Promise<void>;
269
279
  showHookConfirm(title: string, message: string): Promise<boolean>;
270
280
  handleCtrlC(): void;
@@ -8,6 +8,8 @@ export interface ObservableSession {
8
8
  description?: string;
9
9
  status: "active" | "completed" | "failed" | "aborted";
10
10
  sessionFile?: string;
11
+ parentToolCallId?: string;
12
+ index?: number;
11
13
  lastUpdate: number;
12
14
  /** Latest progress snapshot from the subagent executor */
13
15
  progress?: AgentProgress;
@@ -1,3 +1,4 @@
1
+ import { type SgrMouseEvent } from "@oh-my-pi/pi-tui";
1
2
  import type { SetupSceneHost, SetupTab } from "./types";
2
3
  /**
3
4
  * "Sign in" panel: lets the user authenticate one or more model providers via
@@ -15,5 +16,7 @@ export declare class SignInTab implements SetupTab {
15
16
  dispose(): void;
16
17
  invalidate(): void;
17
18
  handleInput(data: string): void;
19
+ /** Forward mouse to the provider selector; pointer is inert during an active login or code prompt. */
20
+ routeMouse(event: SgrMouseEvent, line: number, col: number): void;
18
21
  render(width: number): readonly string[];
19
22
  }
@@ -1,4 +1,4 @@
1
- import type { Component } from "@oh-my-pi/pi-tui";
1
+ import type { Component, SgrMouseEvent } from "@oh-my-pi/pi-tui";
2
2
  import type { InteractiveModeContext } from "../../types";
3
3
  export type SetupSceneResult = "done" | "skipped";
4
4
  export interface SetupSceneHost {
@@ -14,6 +14,13 @@ export interface SetupSceneController extends Component {
14
14
  onMount?(): void | Promise<void>;
15
15
  onUnmount?(): void;
16
16
  dispose?(): void;
17
+ /**
18
+ * Route an SGR mouse report (tracking is on while the wizard holds the
19
+ * alternate screen). `line`/`col` are 0-based within this controller's
20
+ * last rendered output. When absent, the wizard falls back to synthesizing
21
+ * arrow keys from wheel notches.
22
+ */
23
+ routeMouse?(event: SgrMouseEvent, line: number, col: number): void;
17
24
  }
18
25
  /**
19
26
  * A single panel inside a tabbed setup scene. The host scene owns the tab bar
@@ -32,6 +39,8 @@ export interface SetupTab {
32
39
  invalidate(): void;
33
40
  /** Called when the tab becomes active (including initial mount). */
34
41
  onActivate?(): void;
42
+ /** Mouse routing at tab-local coordinates; see {@link SetupSceneController.routeMouse}. */
43
+ routeMouse?(event: SgrMouseEvent, line: number, col: number): void;
35
44
  dispose(): void;
36
45
  }
37
46
  export interface SetupScene {
@@ -1,3 +1,4 @@
1
+ import { type SgrMouseEvent } from "@oh-my-pi/pi-tui";
1
2
  import type { SetupSceneHost, SetupTab } from "./types";
2
3
  /**
3
4
  * "Web search" panel: picks the provider the web_search tool should prefer and
@@ -14,6 +15,8 @@ export declare class WebSearchTab implements SetupTab {
14
15
  constructor(host: SetupSceneHost);
15
16
  onActivate(): void;
16
17
  handleInput(data: string): void;
18
+ /** Wheel moves the highlight; hover lights the row under the pointer; click confirms it. */
19
+ routeMouse(event: SgrMouseEvent, line: number, _col: number): void;
17
20
  invalidate(): void;
18
21
  dispose(): void;
19
22
  render(width: number): readonly string[];
@@ -66,6 +66,7 @@ export interface InteractiveModeContext {
66
66
  pendingMessagesContainer: Container;
67
67
  statusContainer: Container;
68
68
  todoContainer: Container;
69
+ subagentContainer: Container;
69
70
  btwContainer: Container;
70
71
  omfgContainer: Container;
71
72
  errorBannerContainer: Container;
@@ -264,6 +265,7 @@ export interface InteractiveModeContext {
264
265
  handleResumeSession(sessionPath: string): Promise<void>;
265
266
  handleSessionDeleteCommand(): Promise<void>;
266
267
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
268
+ showResetUsageSelector(): Promise<void>;
267
269
  showProviderSetup(): Promise<void>;
268
270
  showHookConfirm(title: string, message: string): Promise<boolean>;
269
271
  showDebugSelector(): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import type { Model } from "@oh-my-pi/pi-ai";
2
2
  import type { Skill } from "../../extensibility/skills";
3
3
  import type { AgentSession } from "../../session/agent-session";
4
+ import { type SnapcompactSavingsEstimate } from "../../session/snapcompact-inline";
4
5
  import type { Tool } from "../../tools";
5
6
  import type { theme as Theme } from "../theme/theme";
6
7
  type CategoryId = "systemPrompt" | "systemContext" | "systemTools" | "skills" | "messages";
@@ -18,6 +19,8 @@ export interface ContextBreakdown {
18
19
  usedTokens: number;
19
20
  autoCompactBufferTokens: number;
20
21
  freeTokens: number;
22
+ /** Estimated snapcompact wire savings; set when requested and a snapcompact.* setting is enabled. */
23
+ snapcompact?: SnapcompactSavingsEstimate;
21
24
  }
22
25
  export declare function estimateSkillsTokens(skills: readonly Skill[]): number;
23
26
  export declare function estimateToolSchemaTokens(tools: ReadonlyArray<Pick<Tool, "name" | "description" | "parameters">>): number;
@@ -38,7 +41,9 @@ export declare function computeNonMessageTokens(session: AgentSession): number;
38
41
  * Compute a breakdown of estimated context usage by category for the active
39
42
  * session and model.
40
43
  */
41
- export declare function computeContextBreakdown(session: AgentSession): ContextBreakdown;
44
+ export declare function computeContextBreakdown(session: AgentSession, options?: {
45
+ snapcompactSavings?: boolean;
46
+ }): ContextBreakdown;
42
47
  /**
43
48
  * Render a colorful context-usage panel as ANSI text. Output is a series of
44
49
  * lines pairing the grid (left) with the legend (right).