@code-yeongyu/senpi 2026.8.27 → 2026.8.28-2

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 (181) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/cli/args.d.ts +2 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +4 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session-services.d.ts.map +1 -1
  7. package/dist/core/agent-session-services.js +2 -0
  8. package/dist/core/agent-session-services.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +5 -0
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +1 -0
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/auth-storage.d.ts +1 -0
  14. package/dist/core/auth-storage.d.ts.map +1 -1
  15. package/dist/core/auth-storage.js +3 -0
  16. package/dist/core/auth-storage.js.map +1 -1
  17. package/dist/core/credential-accounts.d.ts +31 -0
  18. package/dist/core/credential-accounts.d.ts.map +1 -0
  19. package/dist/core/credential-accounts.js +135 -0
  20. package/dist/core/credential-accounts.js.map +1 -0
  21. package/dist/core/credential-pool/classify.d.ts +6 -1
  22. package/dist/core/credential-pool/classify.d.ts.map +1 -1
  23. package/dist/core/credential-pool/classify.js +22 -5
  24. package/dist/core/credential-pool/classify.js.map +1 -1
  25. package/dist/core/credential-pool/failover.d.ts +8 -0
  26. package/dist/core/credential-pool/failover.d.ts.map +1 -1
  27. package/dist/core/credential-pool/failover.js +24 -6
  28. package/dist/core/credential-pool/failover.js.map +1 -1
  29. package/dist/core/credential-pool/rotation-stream.d.ts +13 -2
  30. package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
  31. package/dist/core/credential-pool/rotation-stream.js +97 -10
  32. package/dist/core/credential-pool/rotation-stream.js.map +1 -1
  33. package/dist/core/extensions/builtin/account/index.d.ts +9 -0
  34. package/dist/core/extensions/builtin/account/index.d.ts.map +1 -0
  35. package/dist/core/extensions/builtin/account/index.js +69 -0
  36. package/dist/core/extensions/builtin/account/index.js.map +1 -0
  37. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/goal/index.js +7 -0
  39. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  40. package/dist/core/extensions/builtin/imagegen/index.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/imagegen/index.js +10 -3
  42. package/dist/core/extensions/builtin/imagegen/index.js.map +1 -1
  43. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/index.js +4 -0
  45. package/dist/core/extensions/builtin/index.js.map +1 -1
  46. package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/service-tier.js +13 -0
  48. package/dist/core/extensions/builtin/service-tier.js.map +1 -1
  49. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  50. package/dist/core/extensions/builtin/terminal/extension.js +4 -2
  51. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  52. package/dist/core/model-config-schema.d.ts +4 -4
  53. package/dist/core/model-runtime.d.ts +2 -0
  54. package/dist/core/model-runtime.d.ts.map +1 -1
  55. package/dist/core/model-runtime.js +74 -37
  56. package/dist/core/model-runtime.js.map +1 -1
  57. package/dist/core/retry-fallback/chains.d.ts +23 -1
  58. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  59. package/dist/core/retry-fallback/chains.js +59 -3
  60. package/dist/core/retry-fallback/chains.js.map +1 -1
  61. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  62. package/dist/core/retry-fallback/controller.js +9 -2
  63. package/dist/core/retry-fallback/controller.js.map +1 -1
  64. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  65. package/dist/core/retry-fallback/settings.js +9 -0
  66. package/dist/core/retry-fallback/settings.js.map +1 -1
  67. package/dist/core/retry-fallback/validate.js +1 -1
  68. package/dist/core/retry-fallback/validate.js.map +1 -1
  69. package/dist/core/sdk.js +1 -1
  70. package/dist/core/sdk.js.map +1 -1
  71. package/dist/core/session-manager.d.ts +9 -0
  72. package/dist/core/session-manager.d.ts.map +1 -1
  73. package/dist/core/session-manager.js +31 -0
  74. package/dist/core/session-manager.js.map +1 -1
  75. package/dist/main.d.ts +7 -0
  76. package/dist/main.d.ts.map +1 -1
  77. package/dist/main.js +22 -2
  78. package/dist/main.js.map +1 -1
  79. package/dist/modes/app-server/server/account.d.ts.map +1 -1
  80. package/dist/modes/app-server/server/account.js +5 -5
  81. package/dist/modes/app-server/server/account.js.map +1 -1
  82. package/dist/modes/interactive/components/footer.d.ts +11 -3
  83. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  84. package/dist/modes/interactive/components/footer.js +31 -1
  85. package/dist/modes/interactive/components/footer.js.map +1 -1
  86. package/dist/modes/interactive/grok/chrome.d.ts +4 -4
  87. package/dist/modes/interactive/grok/chrome.d.ts.map +1 -1
  88. package/dist/modes/interactive/grok/chrome.js.map +1 -1
  89. package/dist/modes/interactive/grok/footer.d.ts +3 -3
  90. package/dist/modes/interactive/grok/footer.d.ts.map +1 -1
  91. package/dist/modes/interactive/grok/footer.js.map +1 -1
  92. package/dist/modes/interactive/interactive-host-runtime.d.ts +16 -1
  93. package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
  94. package/dist/modes/interactive/interactive-host-runtime.js +321 -36
  95. package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
  96. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  97. package/dist/modes/interactive/interactive-mode.js +295 -250
  98. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  99. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  100. package/dist/modes/rpc/connection-handler.js +144 -29
  101. package/dist/modes/rpc/connection-handler.js.map +1 -1
  102. package/dist/modes/rpc/multi-session-host.js +14 -4
  103. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  104. package/dist/modes/rpc/rpc-client.d.ts +90 -8
  105. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  106. package/dist/modes/rpc/rpc-client.js +118 -23
  107. package/dist/modes/rpc/rpc-client.js.map +1 -1
  108. package/dist/modes/rpc/rpc-mode.d.ts +3 -1
  109. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  110. package/dist/modes/rpc/rpc-mode.js +3 -1
  111. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  112. package/dist/modes/rpc/rpc-types.d.ts +164 -2
  113. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  114. package/dist/modes/rpc/rpc-types.js.map +1 -1
  115. package/dist/modes/rpc/session-command-router.d.ts +22 -0
  116. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  117. package/dist/modes/rpc/session-command-router.js +153 -14
  118. package/dist/modes/rpc/session-command-router.js.map +1 -1
  119. package/dist/modes/rpc/session-event-writer.d.ts +2 -0
  120. package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
  121. package/dist/modes/rpc/session-event-writer.js +4 -0
  122. package/dist/modes/rpc/session-event-writer.js.map +1 -1
  123. package/dist/modes/rpc/session-registry.d.ts +16 -0
  124. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  125. package/dist/modes/rpc/session-registry.js +40 -3
  126. package/dist/modes/rpc/session-registry.js.map +1 -1
  127. package/docs/providers.md +48 -0
  128. package/docs/rpc.md +43 -4
  129. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +26 -0
  130. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  131. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +13 -1
  132. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/inline-worker.ts +15 -1
  133. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/transport.ts +14 -1
  134. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.d.ts.map +1 -1
  135. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js +20 -4
  136. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js.map +1 -1
  137. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.d.ts +1 -1
  138. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.d.ts.map +1 -1
  139. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/index.js.map +1 -1
  140. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.d.ts +21 -0
  141. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.d.ts.map +1 -0
  142. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.js +27 -0
  143. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/post-mutate.js.map +1 -0
  144. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.d.ts +24 -0
  145. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.d.ts.map +1 -1
  146. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/tool-context.js.map +1 -1
  147. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.d.ts.map +1 -1
  148. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js +7 -2
  149. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/write.js.map +1 -1
  150. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  151. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts +2 -1
  152. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.d.ts.map +1 -1
  153. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js +2 -1
  154. package/node_modules/@earendil-works/pi-ai/dist/auth/credential-store.js.map +1 -1
  155. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +3 -2
  156. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
  157. package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
  158. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  159. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
  160. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  161. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  162. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  163. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  164. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  165. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  166. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  167. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  168. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -1
  169. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
  170. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  171. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  172. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  173. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-cn.json +1 -1
  174. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
  175. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -1
  176. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  177. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  178. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  179. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  180. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  181. package/package.json +7 -7
@@ -1,11 +1,19 @@
1
+ import type { Credential } from "@earendil-works/pi-ai";
1
2
  import { type Component } from "@earendil-works/pi-tui";
2
- import type { AgentSession } from "../../../core/agent-session.ts";
3
3
  import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.ts";
4
+ import type { InteractiveSession } from "../interactive-host-runtime.ts";
4
5
  /**
5
6
  * Format token counts for footer display using oh-my-pi-style K/M/B abbreviation.
6
7
  * Examples: "999", "6.8K", "546K", "1M", "1.5M", "2B".
7
8
  */
8
9
  export declare function formatTokens(count: number): string;
10
+ /**
11
+ * Mirrors the provider-shown-only-when->1 rule for accounts: the active account
12
+ * name appears only when the provider actually pools more than one slot. The
13
+ * pick shown is the pin when present, else the session's HRW winner - the same
14
+ * hash the rotation engine uses, so the footer names the slot that will serve.
15
+ */
16
+ export declare function accountFooterSuffix(credential: Credential | undefined, sessionId: string): string;
9
17
  export declare function formatCwdForFooter(cwd: string, home: string | undefined): string;
10
18
  /**
11
19
  * Footer component that shows pwd, token stats, and context usage.
@@ -15,8 +23,8 @@ export declare class FooterComponent implements Component {
15
23
  private session;
16
24
  private footerData;
17
25
  private autoCompactEnabled;
18
- constructor(session: AgentSession, footerData: ReadonlyFooterDataProvider);
19
- setSession(session: AgentSession): void;
26
+ constructor(session: InteractiveSession, footerData: ReadonlyFooterDataProvider);
27
+ setSession(session: InteractiveSession): void;
20
28
  setAutoCompactEnabled(enabled: boolean): void;
21
29
  /**
22
30
  * No-op: git branch caching now handled by provider.
@@ -1 +1 @@
1
- {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,wBAAwB,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAkBxF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASlD;AAQD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYhF;AAkBD;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,kBAAkB,CAAQ;gBAEtB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B;IAKzE,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAIvC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAsJ/B"}
1
+ {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,EAAE,KAAK,SAAS,EAAiC,MAAM,wBAAwB,CAAC;AACvF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAkBzE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CASjG;AAQD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYhF;AAkBD;;;GAGG;AACH,qBAAa,eAAgB,YAAW,SAAS;IAChD,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,kBAAkB,CAAQ;gBAEtB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,0BAA0B;IAK/E,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAI7C,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI7C;;;OAGG;IACH,UAAU,IAAI,IAAI;IAIlB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAmK/B"}
@@ -1,4 +1,7 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { isAbsolute, relative, resolve, sep } from "node:path";
3
+ import { rendezvousOrder } from "@earendil-works/pi-ai/auth/pool/select";
4
+ import { listSlots } from "@earendil-works/pi-ai/auth/pool/slots";
2
5
  import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
3
6
  import { theme } from "../theme/theme.js";
4
7
  import { planFooterLayout } from "./footer-layout.js";
@@ -34,6 +37,22 @@ export function formatTokens(count) {
34
37
  return `${trim1(n / 1_000_000_000)}B`;
35
38
  return `${Math.round(n / 1_000_000_000)}B`;
36
39
  }
40
+ /**
41
+ * Mirrors the provider-shown-only-when->1 rule for accounts: the active account
42
+ * name appears only when the provider actually pools more than one slot. The
43
+ * pick shown is the pin when present, else the session's HRW winner - the same
44
+ * hash the rotation engine uses, so the footer names the slot that will serve.
45
+ */
46
+ export function accountFooterSuffix(credential, sessionId) {
47
+ const slots = listSlots(credential);
48
+ if (slots.length < 2)
49
+ return "";
50
+ const pinned = Object.entries(credential ?? {}).find(([key]) => key === "pinned")?.[1];
51
+ if (typeof pinned === "string" && slots.some((slot) => slot.name === pinned))
52
+ return `@${pinned}`;
53
+ const winner = rendezvousOrder(sessionId, slots, (input) => createHash("sha256").update(input).digest().readBigUInt64BE(0))[0];
54
+ return winner === undefined ? "" : `@${winner.name}`;
55
+ }
37
56
  /** Format with up to 1 decimal place, dropping trailing `.0`. */
38
57
  function trim1(n) {
39
58
  const s = n.toFixed(1);
@@ -165,7 +184,18 @@ export class FooterComponent {
165
184
  minimalRight = thinkingLevel === "off" ? `${minimalRight}:off` : `${minimalRight}:${thinkingLevel}`;
166
185
  }
167
186
  const minimal = { plain: minimalRight, colored: colorRightSide(minimalRight) };
168
- const providerPrefix = this.footerData.getAvailableProviderCount() > 1 && state.model ? `(${state.model.provider}) ` : "";
187
+ let accountSuffix = "";
188
+ if (state.model) {
189
+ try {
190
+ accountSuffix = accountFooterSuffix(this.session.modelRegistry.authStorage.get(state.model.provider), this.session.sessionManager.getSessionId());
191
+ }
192
+ catch {
193
+ // The footer must render even when credential storage is unreadable.
194
+ }
195
+ }
196
+ const providerPrefix = (this.footerData.getAvailableProviderCount() > 1 || accountSuffix !== "") && state.model
197
+ ? `(${state.model.provider}${accountSuffix}) `
198
+ : "";
169
199
  const full = providerPrefix
170
200
  ? { plain: `${providerPrefix}${minimalRight}`, colored: colorRightSide(`${providerPrefix}${minimalRight}`) }
171
201
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { type FooterSegment, planFooterLayout } from \"./footer-layout.ts\";\n\nconst FAST_MODE_INDICATOR = \"\\u26a1 \";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for footer display using oh-my-pi-style K/M/B abbreviation.\n * Examples: \"999\", \"6.8K\", \"546K\", \"1M\", \"1.5M\", \"2B\".\n */\nexport function formatTokens(count: number): string {\n\tconst n = Math.round(count);\n\tif (n < 1_000) return n.toString();\n\tif (n < 10_000) return `${trim1(n / 1_000)}K`;\n\tif (n < 1_000_000) return `${Math.round(n / 1_000)}K`;\n\tif (n < 10_000_000) return `${trim1(n / 1_000_000)}M`;\n\tif (n < 1_000_000_000) return `${Math.round(n / 1_000_000)}M`;\n\tif (n < 10_000_000_000) return `${trim1(n / 1_000_000_000)}B`;\n\treturn `${Math.round(n / 1_000_000_000)}B`;\n}\n\n/** Format with up to 1 decimal place, dropping trailing `.0`. */\nfunction trim1(n: number): string {\n\tconst s = n.toFixed(1);\n\treturn s.endsWith(\".0\") ? s.slice(0, -2) : s;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/**\n * Color the right side of the footer: (provider) muted, model accent, :thinking dim.\n * The text is the plain (uncolored) right-aligned segment from the layout pass.\n */\nfunction colorRightSide(text: string): string {\n\tif (!text) return \"\";\n\tconst providerMatch = text.match(/^\\(([^)]+)\\) (.*)$/);\n\tconst afterProvider = providerMatch ? providerMatch[2] : text;\n\tconst providerPrefix = providerMatch ? theme.fg(\"muted\", `(${providerMatch[1]}) `) : \"\";\n\tconst fastPrefix = afterProvider.startsWith(FAST_MODE_INDICATOR) ? theme.fg(\"warning\", FAST_MODE_INDICATOR) : \"\";\n\tconst body = fastPrefix ? afterProvider.slice(FAST_MODE_INDICATOR.length) : afterProvider;\n\tconst thinkingMatch = body.match(/^(.+):([^:]+)$/);\n\tif (!thinkingMatch) return providerPrefix + fastPrefix + theme.fg(\"accent\", body);\n\treturn `${providerPrefix}${fastPrefix}${theme.fg(\"accent\", thinkingMatch[1])}${theme.fg(\"dim\", `:${thinkingMatch[2]}`)}`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate session: AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\tprivate autoCompactEnabled = true;\n\n\tconstructor(session: AgentSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// O(1) running totals maintained by SessionManager (identical to summing\n\t\t// usage over all entries; totals are not branch-scoped).\n\t\tconst usageTotals = this.session.sessionManager.getUsageTotals();\n\t\tconst totalCacheRead = usageTotals.cacheRead;\n\t\tconst totalCacheWrite = usageTotals.cacheWrite;\n\t\tconst totalCost = usageTotals.cost;\n\t\tconst latestCacheHitRate = usageTotals.latestCacheHitRate;\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\t\tconst contextTokens =\n\t\t\ttypeof contextUsage?.tokens === \"number\"\n\t\t\t\t? formatTokens(contextUsage.tokens)\n\t\t\t\t: typeof contextUsage?.percent === \"number\"\n\t\t\t\t\t? formatTokens(Math.round((contextWindow * contextUsage.percent) / 100))\n\t\t\t\t\t: \"?\";\n\n\t\t// Segments in priority order: anchors (pwd, branch, context) and the model\n\t\t// label always stay; middle stats elide from the right when space runs out.\n\t\t// The width ladder itself lives in ./footer-layout.ts.\n\t\tconst separator = \" • \";\n\t\tconst sepColored = theme.fg(\"borderMuted\", separator);\n\t\tconst pwdRaw = formatCwdForFooter(\n\t\t\tthis.session.sessionManager.getCwd(),\n\t\t\tprocess.env.HOME || process.env.USERPROFILE,\n\t\t);\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\n\t\tconst anchor: [FooterSegment, ...FooterSegment[]] = [{ plain: pwdRaw, colored: theme.fg(\"accent\", pwdRaw) }];\n\t\tif (branch) anchor.push({ plain: branch, colored: theme.fg(\"warning\", branch) });\n\t\tconst pwdIndex = 0;\n\n\t\tconst dim = (plain: string): FooterSegment => ({ plain, colored: theme.fg(\"dim\", plain) });\n\t\tconst middle: FooterSegment[] = [];\n\t\tif (sessionName) middle.push({ plain: sessionName, colored: theme.fg(\"muted\", sessionName) });\n\t\tif ((totalCacheRead > 0 || totalCacheWrite > 0) && latestCacheHitRate !== undefined && latestCacheHitRate >= 10) {\n\t\t\tmiddle.push(dim(`CH${latestCacheHitRate.toFixed(1)}%`));\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.session.modelRuntime.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tmiddle.push({ plain: costStr, colored: theme.fg(\"success\", costStr) });\n\t\t}\n\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst ctxDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `${contextTokens}/${formatTokens(contextWindow)} (?)${autoIndicator}`\n\t\t\t\t: `${contextTokens}/${formatTokens(contextWindow)} (${contextPercent}%)${autoIndicator}`;\n\t\tconst ctxColored =\n\t\t\tcontextPercentValue > 90\n\t\t\t\t? theme.fg(\"error\", ctxDisplay)\n\t\t\t\t: contextPercentValue > 70\n\t\t\t\t\t? theme.fg(\"warning\", ctxDisplay)\n\t\t\t\t\t: theme.fg(\"muted\", ctxDisplay);\n\t\tconst tail: FooterSegment = { plain: ctxDisplay, colored: ctxColored };\n\n\t\t// Model label pinned to the right edge; the provider prefix stays only when\n\t\t// the full line fits.\n\t\tconst modelName = state.model?.id || \"no-model\";\n\t\tconst fastIndicator = this.session.isFastModeActive() ? FAST_MODE_INDICATOR : \"\";\n\t\tlet minimalRight = `${fastIndicator}${modelName}`;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\tminimalRight = thinkingLevel === \"off\" ? `${minimalRight}:off` : `${minimalRight}:${thinkingLevel}`;\n\t\t}\n\t\tconst minimal: FooterSegment = { plain: minimalRight, colored: colorRightSide(minimalRight) };\n\t\tconst providerPrefix =\n\t\t\tthis.footerData.getAvailableProviderCount() > 1 && state.model ? `(${state.model.provider}) ` : \"\";\n\t\tconst full: FooterSegment | undefined = providerPrefix\n\t\t\t? { plain: `${providerPrefix}${minimalRight}`, colored: colorRightSide(`${providerPrefix}${minimalRight}`) }\n\t\t\t: undefined;\n\n\t\tconst marker: FooterSegment = { plain: \"…\", colored: theme.fg(\"dim\", \"…\") };\n\t\tconst plan = planFooterLayout({\n\t\t\twidth,\n\t\t\tanchor,\n\t\t\tpwdIndex,\n\t\t\tmiddle,\n\t\t\ttail,\n\t\t\tright: { minimal, full },\n\t\t\tseparator,\n\t\t\tminPadding: 2,\n\t\t\tellipsisMarker: marker,\n\t\t});\n\n\t\tconst joinSegments = (segments: readonly FooterSegment[]): { colored: string; width: number } => ({\n\t\t\tcolored: segments.map((segment) => segment.colored).join(sepColored),\n\t\t\twidth: visibleWidth(segments.map((segment) => segment.plain).join(separator)),\n\t\t});\n\n\t\tlet left: { colored: string; width: number };\n\t\tlet right: FooterSegment;\n\t\tif (plan.kind === \"full\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tleft = joinSegments([...anchor, ...middle, tail]);\n\t\t} else if (plan.kind === \"middle-elided\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tconst segments = [...anchor, ...middle.slice(0, plan.keptMiddleCount)];\n\t\t\tif (plan.showMarker) segments.push(marker);\n\t\t\tsegments.push(tail);\n\t\t\tleft = joinSegments(segments);\n\t\t} else if (plan.kind === \"pwd-elided\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tconst segments: FooterSegment[] = [\n\t\t\t\t...anchor.map((segment, index) =>\n\t\t\t\t\tindex === pwdIndex ? { plain: plan.pwdPlain, colored: theme.fg(\"accent\", plan.pwdPlain) } : segment,\n\t\t\t\t),\n\t\t\t\t...middle.slice(0, plan.keptMiddleCount),\n\t\t\t];\n\t\t\tif (plan.showMarker) segments.push(marker);\n\t\t\tsegments.push(tail);\n\t\t\tleft = joinSegments(segments);\n\t\t} else if (plan.kind === \"left-elided\") {\n\t\t\tright = minimal;\n\t\t\tleft = { colored: theme.fg(\"muted\", plan.leftPlain), width: visibleWidth(plan.leftPlain) };\n\t\t} else {\n\t\t\tleft = { colored: \"\", width: 0 };\n\t\t\tright = { plain: plan.rightPlain, colored: colorRightSide(plan.rightPlain) };\n\t\t}\n\n\t\tconst rightWidth = visibleWidth(right.plain);\n\t\tconst padding = \" \".repeat(Math.max(0, width - left.width - rightWidth));\n\t\tconst lines = [left.colored + padding + right.colored];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/footer.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { isAbsolute, relative, resolve, sep } from \"node:path\";\nimport type { Credential } from \"@earendil-works/pi-ai\";\nimport { rendezvousOrder } from \"@earendil-works/pi-ai/auth/pool/select\";\nimport { listSlots } from \"@earendil-works/pi-ai/auth/pool/slots\";\nimport { type Component, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type { InteractiveSession } from \"../interactive-host-runtime.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { type FooterSegment, planFooterLayout } from \"./footer-layout.ts\";\n\nconst FAST_MODE_INDICATOR = \"\\u26a1 \";\n\n/**\n * Sanitize text for display in a single-line status.\n * Removes newlines, tabs, carriage returns, and other control characters.\n */\nfunction sanitizeStatusText(text: string): string {\n\t// Replace newlines, tabs, carriage returns with space, then collapse multiple spaces\n\treturn text\n\t\t.replace(/[\\r\\n\\t]/g, \" \")\n\t\t.replace(/ +/g, \" \")\n\t\t.trim();\n}\n\n/**\n * Format token counts for footer display using oh-my-pi-style K/M/B abbreviation.\n * Examples: \"999\", \"6.8K\", \"546K\", \"1M\", \"1.5M\", \"2B\".\n */\nexport function formatTokens(count: number): string {\n\tconst n = Math.round(count);\n\tif (n < 1_000) return n.toString();\n\tif (n < 10_000) return `${trim1(n / 1_000)}K`;\n\tif (n < 1_000_000) return `${Math.round(n / 1_000)}K`;\n\tif (n < 10_000_000) return `${trim1(n / 1_000_000)}M`;\n\tif (n < 1_000_000_000) return `${Math.round(n / 1_000_000)}M`;\n\tif (n < 10_000_000_000) return `${trim1(n / 1_000_000_000)}B`;\n\treturn `${Math.round(n / 1_000_000_000)}B`;\n}\n\n/**\n * Mirrors the provider-shown-only-when->1 rule for accounts: the active account\n * name appears only when the provider actually pools more than one slot. The\n * pick shown is the pin when present, else the session's HRW winner - the same\n * hash the rotation engine uses, so the footer names the slot that will serve.\n */\nexport function accountFooterSuffix(credential: Credential | undefined, sessionId: string): string {\n\tconst slots = listSlots(credential);\n\tif (slots.length < 2) return \"\";\n\tconst pinned = Object.entries(credential ?? {}).find(([key]) => key === \"pinned\")?.[1];\n\tif (typeof pinned === \"string\" && slots.some((slot) => slot.name === pinned)) return `@${pinned}`;\n\tconst winner = rendezvousOrder(sessionId, slots, (input) =>\n\t\tcreateHash(\"sha256\").update(input).digest().readBigUInt64BE(0),\n\t)[0];\n\treturn winner === undefined ? \"\" : `@${winner.name}`;\n}\n\n/** Format with up to 1 decimal place, dropping trailing `.0`. */\nfunction trim1(n: number): string {\n\tconst s = n.toFixed(1);\n\treturn s.endsWith(\".0\") ? s.slice(0, -2) : s;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n\tif (!home) return cwd;\n\n\tconst resolvedCwd = resolve(cwd);\n\tconst resolvedHome = resolve(home);\n\tconst relativeToHome = relative(resolvedHome, resolvedCwd);\n\tconst isInsideHome =\n\t\trelativeToHome === \"\" ||\n\t\t(relativeToHome !== \"..\" && !relativeToHome.startsWith(`..${sep}`) && !isAbsolute(relativeToHome));\n\n\tif (!isInsideHome) return cwd;\n\treturn relativeToHome === \"\" ? \"~\" : `~${sep}${relativeToHome}`;\n}\n\n/**\n * Color the right side of the footer: (provider) muted, model accent, :thinking dim.\n * The text is the plain (uncolored) right-aligned segment from the layout pass.\n */\nfunction colorRightSide(text: string): string {\n\tif (!text) return \"\";\n\tconst providerMatch = text.match(/^\\(([^)]+)\\) (.*)$/);\n\tconst afterProvider = providerMatch ? providerMatch[2] : text;\n\tconst providerPrefix = providerMatch ? theme.fg(\"muted\", `(${providerMatch[1]}) `) : \"\";\n\tconst fastPrefix = afterProvider.startsWith(FAST_MODE_INDICATOR) ? theme.fg(\"warning\", FAST_MODE_INDICATOR) : \"\";\n\tconst body = fastPrefix ? afterProvider.slice(FAST_MODE_INDICATOR.length) : afterProvider;\n\tconst thinkingMatch = body.match(/^(.+):([^:]+)$/);\n\tif (!thinkingMatch) return providerPrefix + fastPrefix + theme.fg(\"accent\", body);\n\treturn `${providerPrefix}${fastPrefix}${theme.fg(\"accent\", thinkingMatch[1])}${theme.fg(\"dim\", `:${thinkingMatch[2]}`)}`;\n}\n\n/**\n * Footer component that shows pwd, token stats, and context usage.\n * Computes token/context stats from session, gets git branch and extension statuses from provider.\n */\nexport class FooterComponent implements Component {\n\tprivate session: InteractiveSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\tprivate autoCompactEnabled = true;\n\n\tconstructor(session: InteractiveSession, footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t\tthis.footerData = footerData;\n\t}\n\n\tsetSession(session: InteractiveSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(enabled: boolean): void {\n\t\tthis.autoCompactEnabled = enabled;\n\t}\n\n\t/**\n\t * No-op: git branch caching now handled by provider.\n\t * Kept for compatibility with existing call sites in interactive-mode.\n\t */\n\tinvalidate(): void {\n\t\t// No-op: git branch is cached/invalidated by provider\n\t}\n\n\t/**\n\t * Clean up resources.\n\t * Git watcher cleanup now handled by provider.\n\t */\n\tdispose(): void {\n\t\t// Git watcher cleanup handled by provider\n\t}\n\n\trender(width: number): string[] {\n\t\tconst state = this.session.state;\n\n\t\t// O(1) running totals maintained by SessionManager (identical to summing\n\t\t// usage over all entries; totals are not branch-scoped).\n\t\tconst usageTotals = this.session.sessionManager.getUsageTotals();\n\t\tconst totalCacheRead = usageTotals.cacheRead;\n\t\tconst totalCacheWrite = usageTotals.cacheWrite;\n\t\tconst totalCost = usageTotals.cost;\n\t\tconst latestCacheHitRate = usageTotals.latestCacheHitRate;\n\n\t\t// Calculate context usage from session (handles compaction correctly).\n\t\t// After compaction, tokens are unknown until the next LLM response.\n\t\tconst contextUsage = this.session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst contextPercentValue = contextUsage?.percent ?? 0;\n\t\tconst contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : \"?\";\n\t\tconst contextTokens =\n\t\t\ttypeof contextUsage?.tokens === \"number\"\n\t\t\t\t? formatTokens(contextUsage.tokens)\n\t\t\t\t: typeof contextUsage?.percent === \"number\"\n\t\t\t\t\t? formatTokens(Math.round((contextWindow * contextUsage.percent) / 100))\n\t\t\t\t\t: \"?\";\n\n\t\t// Segments in priority order: anchors (pwd, branch, context) and the model\n\t\t// label always stay; middle stats elide from the right when space runs out.\n\t\t// The width ladder itself lives in ./footer-layout.ts.\n\t\tconst separator = \" • \";\n\t\tconst sepColored = theme.fg(\"borderMuted\", separator);\n\t\tconst pwdRaw = formatCwdForFooter(\n\t\t\tthis.session.sessionManager.getCwd(),\n\t\t\tprocess.env.HOME || process.env.USERPROFILE,\n\t\t);\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tconst sessionName = this.session.sessionManager.getSessionName();\n\n\t\tconst anchor: [FooterSegment, ...FooterSegment[]] = [{ plain: pwdRaw, colored: theme.fg(\"accent\", pwdRaw) }];\n\t\tif (branch) anchor.push({ plain: branch, colored: theme.fg(\"warning\", branch) });\n\t\tconst pwdIndex = 0;\n\n\t\tconst dim = (plain: string): FooterSegment => ({ plain, colored: theme.fg(\"dim\", plain) });\n\t\tconst middle: FooterSegment[] = [];\n\t\tif (sessionName) middle.push({ plain: sessionName, colored: theme.fg(\"muted\", sessionName) });\n\t\tif ((totalCacheRead > 0 || totalCacheWrite > 0) && latestCacheHitRate !== undefined && latestCacheHitRate >= 10) {\n\t\t\tmiddle.push(dim(`CH${latestCacheHitRate.toFixed(1)}%`));\n\t\t}\n\n\t\t// Kimi Coding is subscription-backed despite using API-key authentication.\n\t\tconst usingSubscription = state.model\n\t\t\t? state.model.provider === \"kimi-coding\" || this.session.modelRuntime.isUsingSubscription(state.model.provider)\n\t\t\t: false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tconst costStr = `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`;\n\t\t\tmiddle.push({ plain: costStr, colored: theme.fg(\"success\", costStr) });\n\t\t}\n\n\t\tconst autoIndicator = this.autoCompactEnabled ? \" (auto)\" : \"\";\n\t\tconst ctxDisplay =\n\t\t\tcontextPercent === \"?\"\n\t\t\t\t? `${contextTokens}/${formatTokens(contextWindow)} (?)${autoIndicator}`\n\t\t\t\t: `${contextTokens}/${formatTokens(contextWindow)} (${contextPercent}%)${autoIndicator}`;\n\t\tconst ctxColored =\n\t\t\tcontextPercentValue > 90\n\t\t\t\t? theme.fg(\"error\", ctxDisplay)\n\t\t\t\t: contextPercentValue > 70\n\t\t\t\t\t? theme.fg(\"warning\", ctxDisplay)\n\t\t\t\t\t: theme.fg(\"muted\", ctxDisplay);\n\t\tconst tail: FooterSegment = { plain: ctxDisplay, colored: ctxColored };\n\n\t\t// Model label pinned to the right edge; the provider prefix stays only when\n\t\t// the full line fits.\n\t\tconst modelName = state.model?.id || \"no-model\";\n\t\tconst fastIndicator = this.session.isFastModeActive() ? FAST_MODE_INDICATOR : \"\";\n\t\tlet minimalRight = `${fastIndicator}${modelName}`;\n\t\tif (state.model?.reasoning) {\n\t\t\tconst thinkingLevel = state.thinkingLevel || \"off\";\n\t\t\tminimalRight = thinkingLevel === \"off\" ? `${minimalRight}:off` : `${minimalRight}:${thinkingLevel}`;\n\t\t}\n\t\tconst minimal: FooterSegment = { plain: minimalRight, colored: colorRightSide(minimalRight) };\n\t\tlet accountSuffix = \"\";\n\t\tif (state.model) {\n\t\t\ttry {\n\t\t\t\taccountSuffix = accountFooterSuffix(\n\t\t\t\t\tthis.session.modelRegistry.authStorage.get(state.model.provider),\n\t\t\t\t\tthis.session.sessionManager.getSessionId(),\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\t// The footer must render even when credential storage is unreadable.\n\t\t\t}\n\t\t}\n\t\tconst providerPrefix =\n\t\t\t(this.footerData.getAvailableProviderCount() > 1 || accountSuffix !== \"\") && state.model\n\t\t\t\t? `(${state.model.provider}${accountSuffix}) `\n\t\t\t\t: \"\";\n\t\tconst full: FooterSegment | undefined = providerPrefix\n\t\t\t? { plain: `${providerPrefix}${minimalRight}`, colored: colorRightSide(`${providerPrefix}${minimalRight}`) }\n\t\t\t: undefined;\n\n\t\tconst marker: FooterSegment = { plain: \"…\", colored: theme.fg(\"dim\", \"…\") };\n\t\tconst plan = planFooterLayout({\n\t\t\twidth,\n\t\t\tanchor,\n\t\t\tpwdIndex,\n\t\t\tmiddle,\n\t\t\ttail,\n\t\t\tright: { minimal, full },\n\t\t\tseparator,\n\t\t\tminPadding: 2,\n\t\t\tellipsisMarker: marker,\n\t\t});\n\n\t\tconst joinSegments = (segments: readonly FooterSegment[]): { colored: string; width: number } => ({\n\t\t\tcolored: segments.map((segment) => segment.colored).join(sepColored),\n\t\t\twidth: visibleWidth(segments.map((segment) => segment.plain).join(separator)),\n\t\t});\n\n\t\tlet left: { colored: string; width: number };\n\t\tlet right: FooterSegment;\n\t\tif (plan.kind === \"full\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tleft = joinSegments([...anchor, ...middle, tail]);\n\t\t} else if (plan.kind === \"middle-elided\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tconst segments = [...anchor, ...middle.slice(0, plan.keptMiddleCount)];\n\t\t\tif (plan.showMarker) segments.push(marker);\n\t\t\tsegments.push(tail);\n\t\t\tleft = joinSegments(segments);\n\t\t} else if (plan.kind === \"pwd-elided\") {\n\t\t\tright = plan.useFullRight && full ? full : minimal;\n\t\t\tconst segments: FooterSegment[] = [\n\t\t\t\t...anchor.map((segment, index) =>\n\t\t\t\t\tindex === pwdIndex ? { plain: plan.pwdPlain, colored: theme.fg(\"accent\", plan.pwdPlain) } : segment,\n\t\t\t\t),\n\t\t\t\t...middle.slice(0, plan.keptMiddleCount),\n\t\t\t];\n\t\t\tif (plan.showMarker) segments.push(marker);\n\t\t\tsegments.push(tail);\n\t\t\tleft = joinSegments(segments);\n\t\t} else if (plan.kind === \"left-elided\") {\n\t\t\tright = minimal;\n\t\t\tleft = { colored: theme.fg(\"muted\", plan.leftPlain), width: visibleWidth(plan.leftPlain) };\n\t\t} else {\n\t\t\tleft = { colored: \"\", width: 0 };\n\t\t\tright = { plain: plan.rightPlain, colored: colorRightSide(plan.rightPlain) };\n\t\t}\n\n\t\tconst rightWidth = visibleWidth(right.plain);\n\t\tconst padding = \" \".repeat(Math.max(0, width - left.width - rightWidth));\n\t\tconst lines = [left.colored + padding + right.colored];\n\n\t\t// Add extension statuses on a single line, sorted by key alphabetically\n\t\tconst extensionStatuses = this.footerData.getExtensionStatuses();\n\t\tif (extensionStatuses.size > 0) {\n\t\t\tconst sortedStatuses = Array.from(extensionStatuses.entries())\n\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t.map(([, text]) => sanitizeStatusText(text));\n\t\t\tconst statusLine = sortedStatuses.join(\" \");\n\t\t\t// Truncate to terminal width with dim ellipsis for consistency with footer style\n\t\t\tlines.push(truncateToWidth(statusLine, width, theme.fg(\"dim\", \"...\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n}\n"]}
@@ -1,13 +1,13 @@
1
1
  import type { Component, EditorOptions, EditorTheme, TUI } from "@earendil-works/pi-tui";
2
- import type { AgentSession } from "../../../core/agent-session.ts";
3
2
  import type { WorkingIndicatorOptions } from "../../../core/extensions/index.ts";
4
3
  import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.ts";
5
4
  import type { KeybindingsManager } from "../../../core/keybindings.ts";
6
5
  import { CustomEditor } from "../components/custom-editor.ts";
7
6
  import { WorkingStatusIndicator } from "../components/status-indicator.ts";
8
7
  import type { ToolExecutionPresentation } from "../components/tool-execution.ts";
8
+ import type { InteractiveSession } from "../interactive-host-runtime.ts";
9
9
  export interface InteractiveFooter extends Component {
10
- setSession(session: AgentSession): void;
10
+ setSession(session: InteractiveSession): void;
11
11
  setAutoCompactEnabled(enabled: boolean): void;
12
12
  invalidate(): void;
13
13
  dispose(): void;
@@ -28,7 +28,7 @@ export interface InteractiveChrome {
28
28
  editorOptions: EditorOptions;
29
29
  }): CustomEditor;
30
30
  getEditorTheme(): EditorTheme;
31
- createFooter(session: AgentSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;
31
+ createFooter(session: InteractiveSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;
32
32
  createWelcomeContent(appName: string, version: string): Component;
33
33
  createWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator;
34
34
  getEditorBorderColor(context: EditorBorderContext): (text: string) => string;
@@ -42,7 +42,7 @@ export declare class GrokChrome implements InteractiveChrome {
42
42
  editorOptions: EditorOptions;
43
43
  }): CustomEditor;
44
44
  getEditorTheme(): EditorTheme;
45
- createFooter(session: AgentSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;
45
+ createFooter(session: InteractiveSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;
46
46
  createWelcomeContent(appName: string, version: string): Component;
47
47
  createWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator;
48
48
  getEditorBorderColor(_context: EditorBorderContext): (text: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAQjF,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IACxC,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,UAAU,IAAI,IAAI,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,MAAM,mBAAmB,GAAG;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;IACrD,gBAAgB,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,GAAG,CAAC;QAAC,WAAW,EAAE,kBAAkB,CAAC;QAAC,aAAa,EAAE,aAAa,CAAA;KAAE,GAAG,YAAY,CAAC;IACpH,cAAc,IAAI,WAAW,CAAC;IAC9B,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B,GAAG,iBAAiB,CAAC;IAC/F,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAClE,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAAC;IAC9G,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,SAAS,EAAE,CAAC;CACnE;AA8DD,qBAAa,UAAW,YAAW,iBAAiB;IACnD,QAAQ,CAAC,gBAAgB,EAAG,MAAM,CAAU;IAE5C,gBAAgB,CAAC,EAChB,EAAE,EACF,WAAW,EACX,aAAa,GACb,EAAE;QACF,EAAE,EAAE,GAAG,CAAC;QACR,WAAW,EAAE,kBAAkB,CAAC;QAChC,aAAa,EAAE,aAAa,CAAC;KAC7B,GAAG,YAAY;IAIhB,cAAc,IAAI,WAAW;IAkB7B,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,0BAA0B,GAAG,iBAAiB;IAI9F,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS;IAIjE,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,GAAG,sBAAsB;IAQ7G,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;IAI7E,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,SAAS,EAAE;CAYlE"}
1
+ {"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACzF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAQzE,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IACnD,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC9C,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,UAAU,IAAI,IAAI,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,MAAM,mBAAmB,GAAG;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;IACrD,gBAAgB,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,GAAG,CAAC;QAAC,WAAW,EAAE,kBAAkB,CAAC;QAAC,aAAa,EAAE,aAAa,CAAA;KAAE,GAAG,YAAY,CAAC;IACpH,cAAc,IAAI,WAAW,CAAC;IAC9B,YAAY,CAAC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,0BAA0B,GAAG,iBAAiB,CAAC;IACrG,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAClE,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAAC;IAC9G,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7E,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,SAAS,EAAE,CAAC;CACnE;AA8DD,qBAAa,UAAW,YAAW,iBAAiB;IACnD,QAAQ,CAAC,gBAAgB,EAAG,MAAM,CAAU;IAE5C,gBAAgB,CAAC,EAChB,EAAE,EACF,WAAW,EACX,aAAa,GACb,EAAE;QACF,EAAE,EAAE,GAAG,CAAC;QACR,WAAW,EAAE,kBAAkB,CAAC;QAChC,aAAa,EAAE,aAAa,CAAC;KAC7B,GAAG,YAAY;IAIhB,cAAc,IAAI,WAAW;IAkB7B,YAAY,CAAC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,0BAA0B,GAAG,iBAAiB;IAIpG,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS;IAIjE,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,uBAAuB,GAAG,sBAAsB;IAQ7G,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;IAI7E,WAAW,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,GAAG,SAAS,EAAE;CAYlE"}
@@ -1 +1 @@
1
- {"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/chrome.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, EditorOptions, EditorTheme, TUI } from \"@earendil-works/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type { KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { CustomEditor } from \"../components/custom-editor.ts\";\nimport { WorkingStatusIndicator } from \"../components/status-indicator.ts\";\nimport type { ToolExecutionPresentation } from \"../components/tool-execution.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { getGrokChromeTokens } from \"./chrome-tokens.ts\";\nimport { GrokFooter } from \"./footer.ts\";\nimport { GrokInputCard } from \"./input-card.ts\";\nimport { GROK_GLYPHS } from \"./palette.ts\";\nimport { GrokWelcomeCard } from \"./welcome-card.ts\";\n\nexport interface InteractiveFooter extends Component {\n\tsetSession(session: AgentSession): void;\n\tsetAutoCompactEnabled(enabled: boolean): void;\n\tinvalidate(): void;\n\tdispose(): void;\n}\n\nexport type EditorBorderContext = {\n\treadonly isBashMode: boolean;\n\treadonly thinkingLevel: string;\n};\n\n/**\n * Mode-owned chrome seam for InteractiveMode. Extensions continue to own their\n * editor factory; this strategy only creates and decorates the base editor.\n */\nexport interface InteractiveChrome {\n\treadonly toolPresentation: ToolExecutionPresentation;\n\tcreateBaseEditor(context: { ui: TUI; keybindings: KeybindingsManager; editorOptions: EditorOptions }): CustomEditor;\n\tgetEditorTheme(): EditorTheme;\n\tcreateFooter(session: AgentSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;\n\tcreateWelcomeContent(appName: string, version: string): Component;\n\tcreateWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator;\n\tgetEditorBorderColor(context: EditorBorderContext): (text: string) => string;\n\tarrangeRoot(children: readonly Component[], ui?: TUI): Component[];\n}\n\nclass GrokFooterSurface implements Component {\n\tprivate readonly content: Component;\n\n\tconstructor(content: Component) {\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst surface = getGrokChromeTokens().surface;\n\t\treturn this.content.render(width).map(surface);\n\t}\n\n\tdispose(): void {\n\t\tthis.content.dispose?.();\n\t}\n}\n\nclass GrokRootSpacer implements Component {\n\tprivate readonly ui: TUI;\n\tprivate readonly content: readonly Component[];\n\n\tconstructor(ui: TUI, content: readonly Component[]) {\n\t\tthis.ui = ui;\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {\n\t\t// The spacer derives its height from the current terminal dimensions.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst contentHeight = this.content.reduce((height, component) => height + component.render(width).length, 0);\n\t\treturn Array.from({ length: Math.max(0, this.ui.terminal.rows - contentHeight) }, () => \"\");\n\t}\n}\n\nclass GrokEditor extends CustomEditor {\n\tprivate readonly card: GrokInputCard;\n\n\tconstructor(ui: TUI, editorTheme: EditorTheme, keybindings: KeybindingsManager, options: EditorOptions) {\n\t\tsuper(ui, editorTheme, keybindings, options);\n\t\tthis.card = new GrokInputCard({\n\t\t\trender: (width) => this.renderBase(width),\n\t\t\tinvalidate: () => super.invalidate(),\n\t\t});\n\t}\n\n\toverride render(width: number): string[] {\n\t\treturn this.card.render(width);\n\t}\n\n\tprivate renderBase(width: number): string[] {\n\t\treturn super.render(width);\n\t}\n}\n\nexport class GrokChrome implements InteractiveChrome {\n\treadonly toolPresentation = \"grok\" as const;\n\n\tcreateBaseEditor({\n\t\tui,\n\t\tkeybindings,\n\t\teditorOptions,\n\t}: {\n\t\tui: TUI;\n\t\tkeybindings: KeybindingsManager;\n\t\teditorOptions: EditorOptions;\n\t}): CustomEditor {\n\t\treturn new GrokEditor(ui, this.getEditorTheme(), keybindings, editorOptions);\n\t}\n\n\tgetEditorTheme(): EditorTheme {\n\t\tconst tokens = getGrokChromeTokens();\n\t\treturn {\n\t\t\tborderColor: tokens.inputBorder,\n\t\t\tselectList: {\n\t\t\t\tselectedPrefix: (text) => theme.fg(\"accent\", text),\n\t\t\t\tselectedText: (text) => tokens.primaryText(text),\n\t\t\t\tdescription: (text) => tokens.mutedText(text),\n\t\t\t\tscrollInfo: (text) => tokens.mutedText(text),\n\t\t\t\tnoMatch: (text) => tokens.mutedText(text),\n\t\t\t\trenderRow: ({ prefix, primary, description, isSelected }) => {\n\t\t\t\t\tconst row = `${prefix}${tokens.primaryText(primary)}${description ? tokens.mutedText(description) : \"\"}`;\n\t\t\t\t\treturn isSelected ? theme.bg(\"selectedBg\", row) : row;\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\tcreateFooter(session: AgentSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter {\n\t\treturn new GrokFooter(session, footerData);\n\t}\n\n\tcreateWelcomeContent(appName: string, version: string): Component {\n\t\treturn new GrokWelcomeCard(appName, version);\n\t}\n\n\tcreateWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator {\n\t\treturn new WorkingStatusIndicator(ui, message, {\n\t\t\t...indicator,\n\t\t\tframes: [GROK_GLYPHS.spinner],\n\t\t\tindicatorFormatter: (frame) => theme.fg(\"accent\", frame),\n\t\t});\n\t}\n\n\tgetEditorBorderColor(_context: EditorBorderContext): (text: string) => string {\n\t\treturn getGrokChromeTokens().inputBorder;\n\t}\n\n\tarrangeRoot(children: readonly Component[], ui?: TUI): Component[] {\n\t\t// pi-tui concatenates root children without a layout pass. Keep transcript\n\t\t// content first and calculate the remaining rows at render time from the TUI's\n\t\t// terminal height, so the input tail is truly bottom-anchored when it fits.\n\t\tconst inputTailStart = Math.max(0, children.length - 3);\n\t\tconst content = children.slice(0, inputTailStart);\n\t\tconst inputTail = children.slice(inputTailStart);\n\t\tconst footer = inputTail.at(-1);\n\t\tconst tail = footer ? [...inputTail.slice(0, -1), new GrokFooterSurface(footer)] : [...inputTail];\n\t\tconst arranged = [...content, ...tail];\n\t\treturn ui ? [...content, new GrokRootSpacer(ui, arranged), ...tail] : arranged;\n\t}\n}\n"]}
1
+ {"version":3,"file":"chrome.js","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/chrome.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, EditorOptions, EditorTheme, TUI } from \"@earendil-works/pi-tui\";\nimport type { WorkingIndicatorOptions } from \"../../../core/extensions/index.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type { KeybindingsManager } from \"../../../core/keybindings.ts\";\nimport { CustomEditor } from \"../components/custom-editor.ts\";\nimport { WorkingStatusIndicator } from \"../components/status-indicator.ts\";\nimport type { ToolExecutionPresentation } from \"../components/tool-execution.ts\";\nimport type { InteractiveSession } from \"../interactive-host-runtime.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { getGrokChromeTokens } from \"./chrome-tokens.ts\";\nimport { GrokFooter } from \"./footer.ts\";\nimport { GrokInputCard } from \"./input-card.ts\";\nimport { GROK_GLYPHS } from \"./palette.ts\";\nimport { GrokWelcomeCard } from \"./welcome-card.ts\";\n\nexport interface InteractiveFooter extends Component {\n\tsetSession(session: InteractiveSession): void;\n\tsetAutoCompactEnabled(enabled: boolean): void;\n\tinvalidate(): void;\n\tdispose(): void;\n}\n\nexport type EditorBorderContext = {\n\treadonly isBashMode: boolean;\n\treadonly thinkingLevel: string;\n};\n\n/**\n * Mode-owned chrome seam for InteractiveMode. Extensions continue to own their\n * editor factory; this strategy only creates and decorates the base editor.\n */\nexport interface InteractiveChrome {\n\treadonly toolPresentation: ToolExecutionPresentation;\n\tcreateBaseEditor(context: { ui: TUI; keybindings: KeybindingsManager; editorOptions: EditorOptions }): CustomEditor;\n\tgetEditorTheme(): EditorTheme;\n\tcreateFooter(session: InteractiveSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter;\n\tcreateWelcomeContent(appName: string, version: string): Component;\n\tcreateWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator;\n\tgetEditorBorderColor(context: EditorBorderContext): (text: string) => string;\n\tarrangeRoot(children: readonly Component[], ui?: TUI): Component[];\n}\n\nclass GrokFooterSurface implements Component {\n\tprivate readonly content: Component;\n\n\tconstructor(content: Component) {\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.content.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst surface = getGrokChromeTokens().surface;\n\t\treturn this.content.render(width).map(surface);\n\t}\n\n\tdispose(): void {\n\t\tthis.content.dispose?.();\n\t}\n}\n\nclass GrokRootSpacer implements Component {\n\tprivate readonly ui: TUI;\n\tprivate readonly content: readonly Component[];\n\n\tconstructor(ui: TUI, content: readonly Component[]) {\n\t\tthis.ui = ui;\n\t\tthis.content = content;\n\t}\n\n\tinvalidate(): void {\n\t\t// The spacer derives its height from the current terminal dimensions.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst contentHeight = this.content.reduce((height, component) => height + component.render(width).length, 0);\n\t\treturn Array.from({ length: Math.max(0, this.ui.terminal.rows - contentHeight) }, () => \"\");\n\t}\n}\n\nclass GrokEditor extends CustomEditor {\n\tprivate readonly card: GrokInputCard;\n\n\tconstructor(ui: TUI, editorTheme: EditorTheme, keybindings: KeybindingsManager, options: EditorOptions) {\n\t\tsuper(ui, editorTheme, keybindings, options);\n\t\tthis.card = new GrokInputCard({\n\t\t\trender: (width) => this.renderBase(width),\n\t\t\tinvalidate: () => super.invalidate(),\n\t\t});\n\t}\n\n\toverride render(width: number): string[] {\n\t\treturn this.card.render(width);\n\t}\n\n\tprivate renderBase(width: number): string[] {\n\t\treturn super.render(width);\n\t}\n}\n\nexport class GrokChrome implements InteractiveChrome {\n\treadonly toolPresentation = \"grok\" as const;\n\n\tcreateBaseEditor({\n\t\tui,\n\t\tkeybindings,\n\t\teditorOptions,\n\t}: {\n\t\tui: TUI;\n\t\tkeybindings: KeybindingsManager;\n\t\teditorOptions: EditorOptions;\n\t}): CustomEditor {\n\t\treturn new GrokEditor(ui, this.getEditorTheme(), keybindings, editorOptions);\n\t}\n\n\tgetEditorTheme(): EditorTheme {\n\t\tconst tokens = getGrokChromeTokens();\n\t\treturn {\n\t\t\tborderColor: tokens.inputBorder,\n\t\t\tselectList: {\n\t\t\t\tselectedPrefix: (text) => theme.fg(\"accent\", text),\n\t\t\t\tselectedText: (text) => tokens.primaryText(text),\n\t\t\t\tdescription: (text) => tokens.mutedText(text),\n\t\t\t\tscrollInfo: (text) => tokens.mutedText(text),\n\t\t\t\tnoMatch: (text) => tokens.mutedText(text),\n\t\t\t\trenderRow: ({ prefix, primary, description, isSelected }) => {\n\t\t\t\t\tconst row = `${prefix}${tokens.primaryText(primary)}${description ? tokens.mutedText(description) : \"\"}`;\n\t\t\t\t\treturn isSelected ? theme.bg(\"selectedBg\", row) : row;\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\tcreateFooter(session: InteractiveSession, footerData: ReadonlyFooterDataProvider): InteractiveFooter {\n\t\treturn new GrokFooter(session, footerData);\n\t}\n\n\tcreateWelcomeContent(appName: string, version: string): Component {\n\t\treturn new GrokWelcomeCard(appName, version);\n\t}\n\n\tcreateWorkingIndicator(ui: TUI, message: string, indicator?: WorkingIndicatorOptions): WorkingStatusIndicator {\n\t\treturn new WorkingStatusIndicator(ui, message, {\n\t\t\t...indicator,\n\t\t\tframes: [GROK_GLYPHS.spinner],\n\t\t\tindicatorFormatter: (frame) => theme.fg(\"accent\", frame),\n\t\t});\n\t}\n\n\tgetEditorBorderColor(_context: EditorBorderContext): (text: string) => string {\n\t\treturn getGrokChromeTokens().inputBorder;\n\t}\n\n\tarrangeRoot(children: readonly Component[], ui?: TUI): Component[] {\n\t\t// pi-tui concatenates root children without a layout pass. Keep transcript\n\t\t// content first and calculate the remaining rows at render time from the TUI's\n\t\t// terminal height, so the input tail is truly bottom-anchored when it fits.\n\t\tconst inputTailStart = Math.max(0, children.length - 3);\n\t\tconst content = children.slice(0, inputTailStart);\n\t\tconst inputTail = children.slice(inputTailStart);\n\t\tconst footer = inputTail.at(-1);\n\t\tconst tail = footer ? [...inputTail.slice(0, -1), new GrokFooterSurface(footer)] : [...inputTail];\n\t\tconst arranged = [...content, ...tail];\n\t\treturn ui ? [...content, new GrokRootSpacer(ui, arranged), ...tail] : arranged;\n\t}\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { type Component } from "@earendil-works/pi-tui";
2
- import type { AgentSession } from "../../../core/agent-session.ts";
3
2
  import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.ts";
3
+ import type { InteractiveSession } from "../interactive-host-runtime.ts";
4
4
  /** Compact status footer for grok chrome. */
5
5
  export declare class GrokFooter implements Component {
6
6
  private session;
7
- constructor(session: AgentSession, _footerData: ReadonlyFooterDataProvider);
8
- setSession(session: AgentSession): void;
7
+ constructor(session: InteractiveSession, _footerData: ReadonlyFooterDataProvider);
8
+ setSession(session: InteractiveSession): void;
9
9
  setAutoCompactEnabled(_enabled: boolean): void;
10
10
  invalidate(): void;
11
11
  dispose(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAGxF,6CAA6C;AAC7C,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,0BAA0B;IAI1E,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAIvC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI9C,UAAU,IAAI,IAAI;IAIlB,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAM/B"}
1
+ {"version":3,"file":"footer.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,6CAA6C;AAC7C,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,0BAA0B;IAIhF,UAAU,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAI7C,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAI9C,UAAU,IAAI,IAAI;IAIlB,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAM/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,6CAA6C;AAC7C,MAAM,OAAO,UAAU;IAGtB,YAAY,OAAqB,EAAE,WAAuC;QACzE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,UAAU,CAAC,OAAqB;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,qBAAqB,CAAC,QAAiB;QACtC,6DAA6D;IAC9D,CAAC;IAED,UAAU;QACT,8DAA8D;IAC/D,CAAC;IAED,OAAO;QACN,yCAAyC;IAC1C,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,UAAU,CAAC;QACzD,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;CACD","sourcesContent":["import { type Component, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { getGrokChromeTokens } from \"./chrome-tokens.ts\";\n\n/** Compact status footer for grok chrome. */\nexport class GrokFooter implements Component {\n\tprivate session: AgentSession;\n\n\tconstructor(session: AgentSession, _footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t}\n\n\tsetSession(session: AgentSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(_enabled: boolean): void {\n\t\t// The grok footer intentionally presents model and cwd only.\n\t}\n\n\tinvalidate(): void {\n\t\t// Values are read directly from the session during rendering.\n\t}\n\n\tdispose(): void {\n\t\t// No resources are owned by this footer.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tokens = getGrokChromeTokens();\n\t\tconst cwd = this.session.sessionManager.getCwd();\n\t\tconst model = this.session.state.model?.id ?? \"no-model\";\n\t\treturn [truncateToWidth(`${tokens.cwd(cwd)} ${tokens.modelLabel(model)}`, width, \"\")];\n\t}\n}\n"]}
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../../../src/modes/interactive/grok/footer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,6CAA6C;AAC7C,MAAM,OAAO,UAAU;IAGtB,YAAY,OAA2B,EAAE,WAAuC;QAC/E,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,UAAU,CAAC,OAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,qBAAqB,CAAC,QAAiB;QACtC,6DAA6D;IAC9D,CAAC;IAED,UAAU;QACT,8DAA8D;IAC/D,CAAC;IAED,OAAO;QACN,yCAAyC;IAC1C,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,UAAU,CAAC;QACzD,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;CACD","sourcesContent":["import { type Component, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport type { InteractiveSession } from \"../interactive-host-runtime.ts\";\nimport { getGrokChromeTokens } from \"./chrome-tokens.ts\";\n\n/** Compact status footer for grok chrome. */\nexport class GrokFooter implements Component {\n\tprivate session: InteractiveSession;\n\n\tconstructor(session: InteractiveSession, _footerData: ReadonlyFooterDataProvider) {\n\t\tthis.session = session;\n\t}\n\n\tsetSession(session: InteractiveSession): void {\n\t\tthis.session = session;\n\t}\n\n\tsetAutoCompactEnabled(_enabled: boolean): void {\n\t\t// The grok footer intentionally presents model and cwd only.\n\t}\n\n\tinvalidate(): void {\n\t\t// Values are read directly from the session during rendering.\n\t}\n\n\tdispose(): void {\n\t\t// No resources are owned by this footer.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst tokens = getGrokChromeTokens();\n\t\tconst cwd = this.session.sessionManager.getCwd();\n\t\tconst model = this.session.state.model?.id ?? \"no-model\";\n\t\treturn [truncateToWidth(`${tokens.cwd(cwd)} ${tokens.modelLabel(model)}`, width, \"\")];\n\t}\n}\n"]}
@@ -1,12 +1,27 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import type { AgentSession } from "../../core/agent-session.ts";
1
3
  import type { AgentSessionRuntime } from "../../core/agent-session-runtime.ts";
2
4
  import { type EnsuredHost } from "../rpc/host-ensure.ts";
3
5
  import { type RpcClientEvent } from "../rpc/rpc-client.ts";
4
6
  export declare const INTERACTIVE_HOST_FALLBACK_WARNING = "Warning: shared interactive host unavailable; continuing locally";
5
7
  export interface InteractiveHostWarning {
6
- readonly type: "interactive_host_fallback";
8
+ readonly type: "interactive_host_fallback" | "interactive_host_action_failed";
7
9
  readonly message: string;
8
10
  readonly cause: unknown;
9
11
  }
12
+ /**
13
+ * The session contract InteractiveMode actually runs against. The local
14
+ * AgentSession answers these reads synchronously; the shared-host proxy answers
15
+ * them over RPC. Declaring the union here keeps the proxy honest (no more
16
+ * `as unknown as` lie at the boundary) and lets the compiler find every TUI
17
+ * call site that must await.
18
+ */
19
+ export type InteractiveSession = Omit<AgentSession, "cycleThinkingLevel" | "getAvailableThinkingLevels" | "getSessionStats" | "getUserMessagesForForking"> & {
20
+ cycleThinkingLevel(): ThinkingLevel | undefined | Promise<ThinkingLevel | undefined>;
21
+ getAvailableThinkingLevels(): ThinkingLevel[] | Promise<ThinkingLevel[]>;
22
+ getSessionStats(): ReturnType<AgentSession["getSessionStats"]> | Promise<ReturnType<AgentSession["getSessionStats"]>>;
23
+ getUserMessagesForForking(): ReturnType<AgentSession["getUserMessagesForForking"]> | Promise<ReturnType<AgentSession["getUserMessagesForForking"]>>;
24
+ };
10
25
  export interface InteractiveHostRuntimeOptions {
11
26
  readonly socket: string;
12
27
  readonly agentDir?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"interactive-host-runtime.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-host-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE/E,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtE,eAAO,MAAM,iCAAiC,qEAAqE,CAAC;AAEpH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC3G,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACtD;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CACjD,YAAY,EAAE,mBAAmB,EACjC,OAAO,EAAE,6BAA6B,GACpC,OAAO,CAAC,mBAAmB,CAAC,CA0B9B;AAmMD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhH"}
1
+ {"version":3,"file":"interactive-host-runtime.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-host-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAgD,MAAM,6BAA6B,CAAC;AAC9G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAO/E,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtE,eAAO,MAAM,iCAAiC,qEAAqE,CAAC;AAEpH,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,IAAI,EAAE,2BAA2B,GAAG,gCAAgC,CAAC;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACpC,YAAY,EACZ,oBAAoB,GAAG,4BAA4B,GAAG,iBAAiB,GAAG,2BAA2B,CACrG,GAAG;IACH,kBAAkB,IAAI,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IACrF,0BAA0B,IAAI,aAAa,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IACzE,eAAe,IACZ,UAAU,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,GAC3C,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACxD,yBAAyB,IACtB,UAAU,CAAC,YAAY,CAAC,2BAA2B,CAAC,CAAC,GACrD,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAC3G,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACtD;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CACjD,YAAY,EAAE,mBAAmB,EACjC,OAAO,EAAE,6BAA6B,GACpC,OAAO,CAAC,mBAAmB,CAAC,CAgC9B;AAmgBD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhH"}