induscode 0.1.0__py3-none-any.whl
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.
- induscode/__init__.py +56 -0
- induscode/addons/__init__.py +176 -0
- induscode/addons/contract.py +923 -0
- induscode/addons/dispatch/__init__.py +43 -0
- induscode/addons/dispatch/event_dispatcher.py +348 -0
- induscode/addons/dispatch/tool_interceptor.py +349 -0
- induscode/addons/host.py +469 -0
- induscode/addons/loader.py +314 -0
- induscode/addons/manifest.py +232 -0
- induscode/addons/surface.py +199 -0
- induscode/boot/__init__.py +108 -0
- induscode/boot/auth_vault.py +323 -0
- induscode/boot/boot.py +210 -0
- induscode/boot/contract.py +223 -0
- induscode/boot/invocation.py +117 -0
- induscode/boot/runners/__init__.py +42 -0
- induscode/boot/runners/link_runner.py +82 -0
- induscode/boot/runners/oneshot_runner.py +85 -0
- induscode/boot/runners/registry.py +46 -0
- induscode/boot/runners/repl_runner.py +340 -0
- induscode/boot/runners/session.py +549 -0
- induscode/boot/stages.py +198 -0
- induscode/boot/upgrade/__init__.py +36 -0
- induscode/boot/upgrade/apply.py +125 -0
- induscode/boot/upgrade/upgrades.py +136 -0
- induscode/briefing/__init__.py +115 -0
- induscode/briefing/compose.py +414 -0
- induscode/briefing/contract.py +528 -0
- induscode/briefing/macros.py +721 -0
- induscode/briefing/skills.py +417 -0
- induscode/capability_deck/__init__.py +233 -0
- induscode/capability_deck/bridge_ledger/__init__.py +66 -0
- induscode/capability_deck/bridge_ledger/key.py +181 -0
- induscode/capability_deck/bridge_ledger/ledger.py +276 -0
- induscode/capability_deck/bridge_ledger/network.py +336 -0
- induscode/capability_deck/builtin_bridge.py +358 -0
- induscode/capability_deck/cards/__init__.py +116 -0
- induscode/capability_deck/cards/bg_process.py +482 -0
- induscode/capability_deck/cards/memory.py +226 -0
- induscode/capability_deck/cards/saas.py +280 -0
- induscode/capability_deck/cards/task.py +256 -0
- induscode/capability_deck/cards/todo.py +312 -0
- induscode/capability_deck/contract.py +450 -0
- induscode/capability_deck/manifest.py +126 -0
- induscode/capability_deck/provision.py +217 -0
- induscode/channels/__init__.py +146 -0
- induscode/channels/contract.py +585 -0
- induscode/channels/framer.py +132 -0
- induscode/channels/link/__init__.py +50 -0
- induscode/channels/link/dialog.py +246 -0
- induscode/channels/link/driver.py +308 -0
- induscode/channels/link/server.py +217 -0
- induscode/channels/oneshot.py +178 -0
- induscode/channels/ops.py +140 -0
- induscode/channels/session_ops.py +172 -0
- induscode/conductor/__init__.py +240 -0
- induscode/conductor/catalog.py +309 -0
- induscode/conductor/conductor.py +1084 -0
- induscode/conductor/contract.py +1035 -0
- induscode/conductor/matcher.py +291 -0
- induscode/conductor/serialize.py +575 -0
- induscode/conductor/signal_hub.py +382 -0
- induscode/conductor/skill_parse.py +294 -0
- induscode/conductor/transcript_store.py +449 -0
- induscode/console/__init__.py +236 -0
- induscode/console/app.py +1677 -0
- induscode/console/components/__init__.py +62 -0
- induscode/console/components/banner.py +499 -0
- induscode/console/components/banner_sweep.py +188 -0
- induscode/console/components/emblem.py +181 -0
- induscode/console/components/status_bar.py +102 -0
- induscode/console/contract.py +836 -0
- induscode/console/input/__init__.py +107 -0
- induscode/console/input/chord.py +197 -0
- induscode/console/input/dir_reader.py +113 -0
- induscode/console/input/intents.py +258 -0
- induscode/console/input/providers.py +469 -0
- induscode/console/mount.py +137 -0
- induscode/console/overlays/__init__.py +94 -0
- induscode/console/overlays/auth.py +503 -0
- induscode/console/overlays/pickers.py +526 -0
- induscode/console/overlays/router.py +129 -0
- induscode/console/overlays/sessions.py +232 -0
- induscode/console/reducer.py +145 -0
- induscode/console/resume_picker.py +156 -0
- induscode/console/slash_commands/__init__.py +78 -0
- induscode/console/slash_commands/builtins.py +254 -0
- induscode/console/slash_commands/dynamic.py +217 -0
- induscode/console/slash_commands/integrations.py +949 -0
- induscode/console/slash_commands/transcript.py +404 -0
- induscode/console/slash_commands/workbench.py +430 -0
- induscode/console/startup.py +434 -0
- induscode/console/theme/__init__.py +44 -0
- induscode/console/theme/adapter.py +168 -0
- induscode/console/theme/palette.py +128 -0
- induscode/console/theme/resolve.py +123 -0
- induscode/console/theme/tokens.py +185 -0
- induscode/console_slash/__init__.py +111 -0
- induscode/console_slash/contract.py +185 -0
- induscode/console_slash/registry.py +140 -0
- induscode/console_slash/resolve.py +194 -0
- induscode/console_slash/shared.py +172 -0
- induscode/entry.py +108 -0
- induscode/insight/__init__.py +153 -0
- induscode/insight/collector.py +73 -0
- induscode/insight/replay.py +305 -0
- induscode/insight/wrapper.py +1115 -0
- induscode/kit/__init__.py +82 -0
- induscode/kit/clipboard_image.py +215 -0
- induscode/kit/external_editor.py +120 -0
- induscode/kit/image.py +188 -0
- induscode/kit/shell.py +89 -0
- induscode/kit/tool_fetch.py +288 -0
- induscode/launch/__init__.py +224 -0
- induscode/launch/catalog.py +310 -0
- induscode/launch/contract.py +569 -0
- induscode/launch/credentials.py +852 -0
- induscode/launch/invocation/__init__.py +39 -0
- induscode/launch/invocation/attachments.py +281 -0
- induscode/launch/invocation/flags.py +210 -0
- induscode/launch/invocation/read.py +369 -0
- induscode/launch/invocation/usage.py +110 -0
- induscode/launch/oauth.py +808 -0
- induscode/launch/packages.py +299 -0
- induscode/launch/pickers.py +291 -0
- induscode/py.typed +0 -0
- induscode/runtime_bridge/__init__.py +166 -0
- induscode/runtime_bridge/bridges/__init__.py +66 -0
- induscode/runtime_bridge/bridges/_drive.py +268 -0
- induscode/runtime_bridge/bridges/builtins.py +177 -0
- induscode/runtime_bridge/bridges/claude_cli.py +198 -0
- induscode/runtime_bridge/bridges/codex_cli.py +203 -0
- induscode/runtime_bridge/bridges/indusagi_cli.py +217 -0
- induscode/runtime_bridge/broker.py +397 -0
- induscode/runtime_bridge/contract.py +734 -0
- induscode/runtime_bridge/sink.py +351 -0
- induscode/sessions/__init__.py +25 -0
- induscode/sessions/contract.py +119 -0
- induscode/sessions/library.py +350 -0
- induscode/settings/__init__.py +47 -0
- induscode/settings/contract.py +313 -0
- induscode/settings/manager.py +268 -0
- induscode/transcript_export/__init__.py +109 -0
- induscode/transcript_export/contract.py +522 -0
- induscode/transcript_export/publish.py +455 -0
- induscode/transcript_export/sgr.py +566 -0
- induscode/transcript_export/template.py +319 -0
- induscode/transcript_export/theme_bridge.py +325 -0
- induscode/window_budget/__init__.py +76 -0
- induscode/window_budget/budget/__init__.py +26 -0
- induscode/window_budget/budget/estimate.py +273 -0
- induscode/window_budget/budget/gate.py +60 -0
- induscode/window_budget/budget/slice.py +145 -0
- induscode/window_budget/condenser.py +170 -0
- induscode/window_budget/contract.py +329 -0
- induscode/window_budget/summarize/__init__.py +33 -0
- induscode/window_budget/summarize/condense.py +212 -0
- induscode/window_budget/summarize/prompt.py +241 -0
- induscode/workspace/__init__.py +30 -0
- induscode/workspace/brand.py +96 -0
- induscode/workspace/locator.py +269 -0
- induscode-0.1.0.dist-info/METADATA +97 -0
- induscode-0.1.0.dist-info/RECORD +167 -0
- induscode-0.1.0.dist-info/WHEEL +4 -0
- induscode-0.1.0.dist-info/entry_points.txt +3 -0
- induscode-0.1.0.dist-info/licenses/CREDITS.md +22 -0
- induscode-0.1.0.dist-info/licenses/NOTICE +7 -0
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
"""Console contract — the FROZEN type surface of the interactive terminal shell.
|
|
2
|
+
|
|
3
|
+
Port of TS ``src/console/contract.ts``. This module is the single typed seam
|
|
4
|
+
between the coding-agent *product* and the Textual front-end that drives a
|
|
5
|
+
session from a live terminal. It declares *only* shapes plus a handful of tiny
|
|
6
|
+
inert helpers (a scheme-name guard, a fresh empty-state constant, and a pure
|
|
7
|
+
modal transition) — no rendering, no key handlers, no I/O. Every later console
|
|
8
|
+
module (the reducer, the theme engine, the startup gatherer, and the M5-wave-2
|
|
9
|
+
``ConsoleApp`` surface) is written against the names declared here, so the
|
|
10
|
+
file is intentionally small, append-mostly, and stable.
|
|
11
|
+
|
|
12
|
+
Design stance — the shell is *wiring*, not widgets:
|
|
13
|
+
|
|
14
|
+
1. **One immutable reducer state.** The terminal surface's UI-local state is
|
|
15
|
+
reduced from a single :class:`ConsoleState` value mutated only through a
|
|
16
|
+
:data:`ConsoleEvent` action union dispatched into
|
|
17
|
+
:func:`induscode.console.reducer.console_reducer`. The discriminants are
|
|
18
|
+
the console's own ``domain:verb`` vocabulary, kept verbatim from TS.
|
|
19
|
+
2. **A data-driven slash registry.** Slash commands are rows in a
|
|
20
|
+
:class:`SlashRegistry`, never an ``if``-ladder — the whole slash framework
|
|
21
|
+
already landed as :mod:`induscode.console_slash` (M1) and is re-exported
|
|
22
|
+
here so console consumers import one surface.
|
|
23
|
+
3. **Theme behind the framework adapter.** The console speaks in semantic
|
|
24
|
+
:class:`ThemeTokens`; the concrete terminal colours are produced once, at
|
|
25
|
+
the config-load boundary, by mapping a :class:`ThemePalette` through the
|
|
26
|
+
framework ``create_theme_bundle``. The accent ramp is the console's own.
|
|
27
|
+
4. **The console drives a conductor.** :class:`ConsoleProps` carries a
|
|
28
|
+
``SessionConductor``; the surface subscribes to its ``SessionSignal``
|
|
29
|
+
stream and renders its ``ConductorState``. The conductor surface is the
|
|
30
|
+
runtime contract and is never re-declared here.
|
|
31
|
+
|
|
32
|
+
Port deltas (locked by the port plan, analysis 02 §7):
|
|
33
|
+
|
|
34
|
+
- **Composer buffer / caret / history are GONE.** The TS reducer owned a
|
|
35
|
+
hand-rolled single-line editor (``buffer``/``caret``/``history``/
|
|
36
|
+
``historyAt``/``stash`` state; ``buffer:*``/``caret:*``/``history:*``
|
|
37
|
+
events). The Python build delegates all of that to the framework's
|
|
38
|
+
``EditorCore``-backed ``PromptEditor``, so :class:`ConsoleState` keeps only
|
|
39
|
+
the rows/blocks/modal/status/scheme/toggles/busy slices and the event union
|
|
40
|
+
drops the editor families.
|
|
41
|
+
- **``Themed`` / ``RenderSlot`` are dropped** — Textual CSS variables and
|
|
42
|
+
``compose()`` replace the per-component theme prop and the ReactNode slot.
|
|
43
|
+
- ``ConsoleEventOf`` (TS type-level extraction) is replaced by the
|
|
44
|
+
:data:`CONSOLE_EVENT_TYPES` tuple plus a reducer key-coverage test, per the
|
|
45
|
+
cross-cutting exhaustiveness rule.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
from collections.abc import Awaitable, Callable
|
|
51
|
+
from dataclasses import dataclass
|
|
52
|
+
from typing import ClassVar, Final, Literal, Protocol, TypeAlias, TypeGuard
|
|
53
|
+
|
|
54
|
+
from indusagi.react_ink import (
|
|
55
|
+
InkThemeAdapter,
|
|
56
|
+
SessionSnapshot,
|
|
57
|
+
StatusMessage,
|
|
58
|
+
ThemeBundle,
|
|
59
|
+
ToolExecutionState,
|
|
60
|
+
UiDisplayBlock,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
from induscode.conductor import ConductorState, SessionConductor, SessionSignal
|
|
64
|
+
from induscode.console_slash import (
|
|
65
|
+
Handled,
|
|
66
|
+
OpenModal,
|
|
67
|
+
Prompt,
|
|
68
|
+
SlashCommand,
|
|
69
|
+
SlashContext,
|
|
70
|
+
SlashOutcome,
|
|
71
|
+
SlashRegistry,
|
|
72
|
+
SlashRun,
|
|
73
|
+
Unknown,
|
|
74
|
+
)
|
|
75
|
+
from induscode.launch import (
|
|
76
|
+
AuthVault,
|
|
77
|
+
LoginProvider,
|
|
78
|
+
OAuthLoginCallbacks,
|
|
79
|
+
OAuthLoginResult,
|
|
80
|
+
)
|
|
81
|
+
from induscode.sessions import SessionLibrary
|
|
82
|
+
from induscode.settings import PreferenceStore
|
|
83
|
+
|
|
84
|
+
__all__ = [
|
|
85
|
+
"BlockAppend",
|
|
86
|
+
"BlocksClear",
|
|
87
|
+
"BusySet",
|
|
88
|
+
"CONSOLE_EVENT_TYPES",
|
|
89
|
+
"ConductorState",
|
|
90
|
+
"ConsoleDispatch",
|
|
91
|
+
"ConsoleEvent",
|
|
92
|
+
"ConsoleEventType",
|
|
93
|
+
"ConsoleHost",
|
|
94
|
+
"ConsoleProps",
|
|
95
|
+
"ConsoleReducer",
|
|
96
|
+
"ConsoleState",
|
|
97
|
+
"ConsoleTheme",
|
|
98
|
+
"DEFAULT_SCHEME",
|
|
99
|
+
"EMPTY_CONSOLE_STATE",
|
|
100
|
+
"Handled",
|
|
101
|
+
"InkThemeAdapter",
|
|
102
|
+
"MODAL_KINDS",
|
|
103
|
+
"ModalClose",
|
|
104
|
+
"ModalKind",
|
|
105
|
+
"ModalOpen",
|
|
106
|
+
"ModalState",
|
|
107
|
+
"NO_MODAL",
|
|
108
|
+
"OpenModal",
|
|
109
|
+
"OverlayServices",
|
|
110
|
+
"Prompt",
|
|
111
|
+
"RowsAppend",
|
|
112
|
+
"RowsPatch",
|
|
113
|
+
"RowsSet",
|
|
114
|
+
"SchemeSet",
|
|
115
|
+
"SessionConductor",
|
|
116
|
+
"SessionSignal",
|
|
117
|
+
"SessionSnapshot",
|
|
118
|
+
"SlashCommand",
|
|
119
|
+
"SlashContext",
|
|
120
|
+
"SlashOutcome",
|
|
121
|
+
"SlashRegistry",
|
|
122
|
+
"SlashRun",
|
|
123
|
+
"StartOAuthLogin",
|
|
124
|
+
"StatusClear",
|
|
125
|
+
"StatusMessage",
|
|
126
|
+
"StatusSet",
|
|
127
|
+
"THEME_TOKEN_ROLES",
|
|
128
|
+
"ThemePalette",
|
|
129
|
+
"ThemeScheme",
|
|
130
|
+
"ThemeToken",
|
|
131
|
+
"ThemeTokens",
|
|
132
|
+
"Tick",
|
|
133
|
+
"ToggleImages",
|
|
134
|
+
"ToggleReasoning",
|
|
135
|
+
"ToolExecutionState",
|
|
136
|
+
"UiDisplayBlock",
|
|
137
|
+
"Unknown",
|
|
138
|
+
"ViewRow",
|
|
139
|
+
"ViewRowKind",
|
|
140
|
+
"is_theme_scheme",
|
|
141
|
+
"transition_modal",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# Theme — schemes, semantic tokens, and the accent palette
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
#: The built-in colour schemes the console ships with.
|
|
150
|
+
#:
|
|
151
|
+
#: Named for the time-of-day they evoke rather than a bare light/dark axis,
|
|
152
|
+
#: with a daltonized (color-blind-friendly) variant of each:
|
|
153
|
+
#:
|
|
154
|
+
#: - ``midnight`` — a low-luminance scheme for dark terminals.
|
|
155
|
+
#: - ``daylight`` — a high-luminance scheme for light terminals.
|
|
156
|
+
#: - ``midnight-cb`` — the dark scheme re-derived so success vs failure
|
|
157
|
+
#: separates off the red-green axis (success → blue), deuteran/protan-safe.
|
|
158
|
+
#: - ``daylight-cb`` — the light scheme's color-blind-safe counterpart.
|
|
159
|
+
ThemeScheme: TypeAlias = Literal["midnight", "daylight", "midnight-cb", "daylight-cb"]
|
|
160
|
+
|
|
161
|
+
#: The default scheme applied before any user preference is loaded.
|
|
162
|
+
DEFAULT_SCHEME: Final[ThemeScheme] = "midnight"
|
|
163
|
+
|
|
164
|
+
#: The closed scheme-name set the guard validates against.
|
|
165
|
+
_SCHEME_NAMES: Final[frozenset[str]] = frozenset(
|
|
166
|
+
{"midnight", "daylight", "midnight-cb", "daylight-cb"}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def is_theme_scheme(value: str) -> TypeGuard[ThemeScheme]:
|
|
171
|
+
"""Narrow an arbitrary string to a known :data:`ThemeScheme`.
|
|
172
|
+
|
|
173
|
+
The single sanctioned guard for scheme names, so every loader validates
|
|
174
|
+
the same way. Returns ``True`` only for a recognised scheme literal.
|
|
175
|
+
|
|
176
|
+
:param value: any candidate string read from settings or a slash argument
|
|
177
|
+
"""
|
|
178
|
+
return value in _SCHEME_NAMES
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass(frozen=True, slots=True)
|
|
182
|
+
class ThemeTokens:
|
|
183
|
+
"""The semantic colour/style tokens the console renders in.
|
|
184
|
+
|
|
185
|
+
These are *roles*, not literals: a component asks for ``frame`` or
|
|
186
|
+
``signal``, never a hex code. Each token is resolved to a concrete colour
|
|
187
|
+
by the framework :class:`~indusagi.react_ink.InkThemeAdapter` at the
|
|
188
|
+
boundary; the console body never touches a hex value directly. The token
|
|
189
|
+
set is closed (a frozen dataclass), so a scheme that omits one fails at
|
|
190
|
+
construction rather than rendering an undefined colour.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
# The primary accent (active prompt, selection, focus).
|
|
194
|
+
signal: str
|
|
195
|
+
# Default panel/border lines and structural chrome.
|
|
196
|
+
frame: str
|
|
197
|
+
# De-emphasised borders and separators.
|
|
198
|
+
quiet_frame: str
|
|
199
|
+
# The composer's active background tint.
|
|
200
|
+
prompt_surface: str
|
|
201
|
+
# Accent applied to message-row gutters and headers.
|
|
202
|
+
card_accent: str
|
|
203
|
+
# Default foreground for assistant/answer text.
|
|
204
|
+
body_text: str
|
|
205
|
+
# Secondary/metadata text (timestamps, hints).
|
|
206
|
+
muted_text: str
|
|
207
|
+
# High-contrast text on an accented surface.
|
|
208
|
+
ink_text: str
|
|
209
|
+
# Informational status tone.
|
|
210
|
+
notice: str
|
|
211
|
+
# Success status tone.
|
|
212
|
+
affirm: str
|
|
213
|
+
# Warning status tone.
|
|
214
|
+
caution: str
|
|
215
|
+
# Error/fault status tone.
|
|
216
|
+
alarm: str
|
|
217
|
+
# Busy/in-flight status tone.
|
|
218
|
+
pending: str
|
|
219
|
+
# Rich-render roles (markdown / diff / syntax highlighting). These feed
|
|
220
|
+
# the framework adapter's markdown/diff/highlight accessors so the styled
|
|
221
|
+
# transcript, colored diffs, and fenced-code highlighting recolor for
|
|
222
|
+
# free with each scheme.
|
|
223
|
+
# Inline ``code`` foreground.
|
|
224
|
+
code_inline: str
|
|
225
|
+
# Markdown heading foreground.
|
|
226
|
+
heading: str
|
|
227
|
+
# The dim bar drawn beside a blockquote.
|
|
228
|
+
blockquote_bar: str
|
|
229
|
+
# Background tint for an added (``+``) diff line.
|
|
230
|
+
diff_added_bg: str
|
|
231
|
+
# Background tint for a removed (``-``) diff line.
|
|
232
|
+
diff_removed_bg: str
|
|
233
|
+
# Foreground for added-line content / ``+`` marker.
|
|
234
|
+
diff_added_text: str
|
|
235
|
+
# Foreground for removed-line content / ``-`` marker.
|
|
236
|
+
diff_removed_text: str
|
|
237
|
+
# Syntax scope: keywords.
|
|
238
|
+
syn_keyword: str
|
|
239
|
+
# Syntax scope: string literals.
|
|
240
|
+
syn_string: str
|
|
241
|
+
# Syntax scope: numeric literals.
|
|
242
|
+
syn_number: str
|
|
243
|
+
# Syntax scope: comments.
|
|
244
|
+
syn_comment: str
|
|
245
|
+
# Syntax scope: types / classes / built-ins.
|
|
246
|
+
syn_type: str
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
#: One token role name (TS ``ThemeToken = keyof ThemeTokens``).
|
|
250
|
+
ThemeToken: TypeAlias = Literal[
|
|
251
|
+
"signal",
|
|
252
|
+
"frame",
|
|
253
|
+
"quiet_frame",
|
|
254
|
+
"prompt_surface",
|
|
255
|
+
"card_accent",
|
|
256
|
+
"body_text",
|
|
257
|
+
"muted_text",
|
|
258
|
+
"ink_text",
|
|
259
|
+
"notice",
|
|
260
|
+
"affirm",
|
|
261
|
+
"caution",
|
|
262
|
+
"alarm",
|
|
263
|
+
"pending",
|
|
264
|
+
"code_inline",
|
|
265
|
+
"heading",
|
|
266
|
+
"blockquote_bar",
|
|
267
|
+
"diff_added_bg",
|
|
268
|
+
"diff_removed_bg",
|
|
269
|
+
"diff_added_text",
|
|
270
|
+
"diff_removed_text",
|
|
271
|
+
"syn_keyword",
|
|
272
|
+
"syn_string",
|
|
273
|
+
"syn_number",
|
|
274
|
+
"syn_comment",
|
|
275
|
+
"syn_type",
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
#: The closed set of token role names, for iteration and validation (the
|
|
279
|
+
#: Python stand-in for TS ``keyof`` — tests fold over this).
|
|
280
|
+
THEME_TOKEN_ROLES: Final[tuple[ThemeToken, ...]] = (
|
|
281
|
+
"signal",
|
|
282
|
+
"frame",
|
|
283
|
+
"quiet_frame",
|
|
284
|
+
"prompt_surface",
|
|
285
|
+
"card_accent",
|
|
286
|
+
"body_text",
|
|
287
|
+
"muted_text",
|
|
288
|
+
"ink_text",
|
|
289
|
+
"notice",
|
|
290
|
+
"affirm",
|
|
291
|
+
"caution",
|
|
292
|
+
"alarm",
|
|
293
|
+
"pending",
|
|
294
|
+
"code_inline",
|
|
295
|
+
"heading",
|
|
296
|
+
"blockquote_bar",
|
|
297
|
+
"diff_added_bg",
|
|
298
|
+
"diff_removed_bg",
|
|
299
|
+
"diff_added_text",
|
|
300
|
+
"diff_removed_text",
|
|
301
|
+
"syn_keyword",
|
|
302
|
+
"syn_string",
|
|
303
|
+
"syn_number",
|
|
304
|
+
"syn_comment",
|
|
305
|
+
"syn_type",
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@dataclass(frozen=True, slots=True)
|
|
310
|
+
class ThemePalette:
|
|
311
|
+
"""The accent ramp a scheme is derived from — the console's own hex values.
|
|
312
|
+
|
|
313
|
+
A palette is the small raw-colour source from which the full
|
|
314
|
+
:class:`ThemeTokens` map is computed at load time. These nine stops are an
|
|
315
|
+
original ramp (re-derived for this console; they intentionally do not
|
|
316
|
+
reuse any upstream accent values) spanning a cool primary, a warm
|
|
317
|
+
secondary, and a neutral text gradient. The boundary adapter expands them
|
|
318
|
+
into the semantic token map and hands the result to the framework
|
|
319
|
+
``create_theme_bundle``.
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
# Primary accent — the dominant cool hue.
|
|
323
|
+
primary: str
|
|
324
|
+
# Secondary accent — a complementary warm hue.
|
|
325
|
+
secondary: str
|
|
326
|
+
# Tertiary accent — a muted support hue.
|
|
327
|
+
tertiary: str
|
|
328
|
+
# Brightest neutral — high-contrast text.
|
|
329
|
+
ink: str
|
|
330
|
+
# Mid neutral — default body text.
|
|
331
|
+
body: str
|
|
332
|
+
# Dim neutral — secondary/metadata text.
|
|
333
|
+
muted: str
|
|
334
|
+
# Success hue.
|
|
335
|
+
affirm: str
|
|
336
|
+
# Warning hue.
|
|
337
|
+
caution: str
|
|
338
|
+
# Error hue.
|
|
339
|
+
alarm: str
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
@dataclass(frozen=True, slots=True)
|
|
343
|
+
class ConsoleTheme:
|
|
344
|
+
"""A fully resolved scheme: identity, raw ramp, and the semantic token map
|
|
345
|
+
the console renders in.
|
|
346
|
+
|
|
347
|
+
The ``tokens`` are derived from ``palette`` at load time; ``bundle`` is
|
|
348
|
+
the framework projection produced from those tokens — the Rich-painting
|
|
349
|
+
adapter **plus** the registered Textual ``Theme`` and the Pygments style
|
|
350
|
+
(the Python boundary is ``create_theme_bundle``, not the bare adapter).
|
|
351
|
+
A scheme is the unit the theme picker selects.
|
|
352
|
+
"""
|
|
353
|
+
|
|
354
|
+
# Which scheme this resolves.
|
|
355
|
+
scheme: ThemeScheme
|
|
356
|
+
# The raw accent ramp this scheme was derived from.
|
|
357
|
+
palette: ThemePalette
|
|
358
|
+
# The semantic token map components render against.
|
|
359
|
+
tokens: ThemeTokens
|
|
360
|
+
# The framework adapter that turns token roles into terminal colours.
|
|
361
|
+
adapter: InkThemeAdapter
|
|
362
|
+
# The full framework bundle: adapter + Textual Theme + Pygments style.
|
|
363
|
+
bundle: ThemeBundle
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
# ---------------------------------------------------------------------------
|
|
367
|
+
# Transcript view rows
|
|
368
|
+
# ---------------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
#: The discriminant of a single rendered transcript row.
|
|
371
|
+
#:
|
|
372
|
+
#: The console renders its scrollback as a flat list of typed rows rather
|
|
373
|
+
#: than a single message blob, so each kind can be width-packed and themed
|
|
374
|
+
#: independently:
|
|
375
|
+
#:
|
|
376
|
+
#: - ``prompt`` — a user-submitted turn.
|
|
377
|
+
#: - ``answer`` — streamed assistant answer text.
|
|
378
|
+
#: - ``reason`` — streamed reasoning/thinking text (shown only when enabled).
|
|
379
|
+
#: - ``toolRun`` — a tool invocation row, correlated by ``run_id``.
|
|
380
|
+
#: - ``notice`` — an out-of-band notice (changelog, status, system note).
|
|
381
|
+
ViewRowKind: TypeAlias = Literal["prompt", "answer", "reason", "toolRun", "notice"]
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@dataclass(frozen=True, slots=True)
|
|
385
|
+
class ViewRow:
|
|
386
|
+
"""One immutable row in the transcript view.
|
|
387
|
+
|
|
388
|
+
Rows are append-mostly and identity-stable: a streaming
|
|
389
|
+
``answer``/``reason`` row keeps its ``id`` while its ``text`` grows, so
|
|
390
|
+
the renderer can reconcile in place. ``run_id`` correlates a ``toolRun``
|
|
391
|
+
row with its :class:`~indusagi.react_ink.ToolExecutionState` entry.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
# Stable unique row id.
|
|
395
|
+
id: str
|
|
396
|
+
# Which kind of row this is.
|
|
397
|
+
kind: ViewRowKind
|
|
398
|
+
# The row's display text (may be partial while streaming).
|
|
399
|
+
text: str
|
|
400
|
+
# Tool-run correlation id, present only for ``toolRun`` rows.
|
|
401
|
+
run_id: str | None = None
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
# ---------------------------------------------------------------------------
|
|
405
|
+
# Modal / overlay state
|
|
406
|
+
# ---------------------------------------------------------------------------
|
|
407
|
+
|
|
408
|
+
#: The closed set of modal overlays the console can raise over the transcript.
|
|
409
|
+
#:
|
|
410
|
+
#: Exactly one modal is active at a time (or ``none``). The surface renders
|
|
411
|
+
#: the matching framework dialog from a table keyed by this discriminant
|
|
412
|
+
#: rather than a hand-written switch:
|
|
413
|
+
#:
|
|
414
|
+
#: - ``none`` — no overlay; the composer has focus.
|
|
415
|
+
#: - ``settings`` — the settings list.
|
|
416
|
+
#: - ``models`` — the single-model picker.
|
|
417
|
+
#: - ``scopedModels`` — the per-scope model picker.
|
|
418
|
+
#: - ``theme`` — the scheme picker.
|
|
419
|
+
#: - ``sessions`` — the session resume/list picker.
|
|
420
|
+
#: - ``tree`` — the transcript-tree navigator.
|
|
421
|
+
#: - ``userTurns`` — the prior-user-turn picker (for branching/forking).
|
|
422
|
+
#: - ``signIn`` — the provider sign-in launcher.
|
|
423
|
+
#: - ``signOut`` — the provider sign-out confirmation.
|
|
424
|
+
#: - ``oauth`` — the in-flight OAuth device/redirect flow.
|
|
425
|
+
#: - ``plugin`` — a plugin-supplied select/confirm/input/custom overlay.
|
|
426
|
+
ModalKind: TypeAlias = Literal[
|
|
427
|
+
"none",
|
|
428
|
+
"settings",
|
|
429
|
+
"models",
|
|
430
|
+
"scopedModels",
|
|
431
|
+
"theme",
|
|
432
|
+
"sessions",
|
|
433
|
+
"tree",
|
|
434
|
+
"userTurns",
|
|
435
|
+
"signIn",
|
|
436
|
+
"signOut",
|
|
437
|
+
"oauth",
|
|
438
|
+
"plugin",
|
|
439
|
+
]
|
|
440
|
+
|
|
441
|
+
#: The closed modal-kind set, for the overlay dispatch table and its
|
|
442
|
+
#: key-coverage test (TS relied on union exhaustiveness).
|
|
443
|
+
MODAL_KINDS: Final[tuple[ModalKind, ...]] = (
|
|
444
|
+
"none",
|
|
445
|
+
"settings",
|
|
446
|
+
"models",
|
|
447
|
+
"scopedModels",
|
|
448
|
+
"theme",
|
|
449
|
+
"sessions",
|
|
450
|
+
"tree",
|
|
451
|
+
"userTurns",
|
|
452
|
+
"signIn",
|
|
453
|
+
"signOut",
|
|
454
|
+
"oauth",
|
|
455
|
+
"plugin",
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
@dataclass(frozen=True, slots=True)
|
|
460
|
+
class ModalState:
|
|
461
|
+
"""The active modal plus any opaque payload the matching dialog needs.
|
|
462
|
+
|
|
463
|
+
``payload`` is deliberately untyped at the contract layer: each dialog
|
|
464
|
+
narrows it at its own boundary (e.g. the OAuth flow state, a plugin
|
|
465
|
+
overlay request). ``none`` carries no payload.
|
|
466
|
+
"""
|
|
467
|
+
|
|
468
|
+
# Which overlay is currently raised.
|
|
469
|
+
kind: ModalKind
|
|
470
|
+
# Opaque per-modal payload, narrowed by the rendering dialog.
|
|
471
|
+
payload: object | None = None
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
#: The inert "no overlay" modal state.
|
|
475
|
+
NO_MODAL: Final[ModalState] = ModalState(kind="none")
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def transition_modal(next_kind: ModalKind, payload: object | None = None) -> ModalState:
|
|
479
|
+
"""Compute the next :class:`ModalState` for a requested transition.
|
|
480
|
+
|
|
481
|
+
A pure, inert helper so the open/close/replace logic lives in one place
|
|
482
|
+
rather than being re-derived per call site. Opening any kind other than
|
|
483
|
+
``none`` raises that overlay (carrying the optional payload); opening
|
|
484
|
+
``none`` (or closing) returns :data:`NO_MODAL`.
|
|
485
|
+
|
|
486
|
+
:param next_kind: the modal kind to transition to
|
|
487
|
+
:param payload: optional payload for the target overlay
|
|
488
|
+
"""
|
|
489
|
+
if next_kind == "none":
|
|
490
|
+
return NO_MODAL
|
|
491
|
+
return ModalState(kind=next_kind, payload=payload)
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
# ---------------------------------------------------------------------------
|
|
495
|
+
# The reducer state
|
|
496
|
+
# ---------------------------------------------------------------------------
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
@dataclass(frozen=True, slots=True)
|
|
500
|
+
class ConsoleState:
|
|
501
|
+
"""The immutable UI-local state the terminal surface is reduced from.
|
|
502
|
+
|
|
503
|
+
Every observable UI-local property of the console — what is on screen,
|
|
504
|
+
which overlay is up, and the display toggles — is one read-only field
|
|
505
|
+
here. The surface holds exactly one of these and never mutates it in
|
|
506
|
+
place; a :data:`ConsoleEvent` produces a fresh value. Live session data
|
|
507
|
+
(messages, usage, model) is *not* stored here — it is projected from the
|
|
508
|
+
conductor snapshot — and the composer text/caret/history live in the
|
|
509
|
+
framework editor (``EditorCore``), not in this state (port delta; see the
|
|
510
|
+
module docstring).
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
# The rendered transcript, newest row last.
|
|
514
|
+
rows: tuple[ViewRow, ...] = ()
|
|
515
|
+
# Out-of-band display blocks (changelog, etc.) interleaved with the rows.
|
|
516
|
+
blocks: tuple[UiDisplayBlock, ...] = ()
|
|
517
|
+
# The active modal overlay.
|
|
518
|
+
modal: ModalState = NO_MODAL
|
|
519
|
+
# The transient status line, when one is showing.
|
|
520
|
+
status: StatusMessage | None = None
|
|
521
|
+
# The active colour scheme.
|
|
522
|
+
scheme: ThemeScheme = DEFAULT_SCHEME
|
|
523
|
+
# Whether reasoning/thinking rows are shown.
|
|
524
|
+
show_reasoning: bool = False
|
|
525
|
+
# Whether inline images are rendered.
|
|
526
|
+
show_images: bool = True
|
|
527
|
+
# Whether a turn is in flight (input disabled / spinner shown).
|
|
528
|
+
busy: bool = False
|
|
529
|
+
# Monotonic tick that forces a status-bar re-render on data change.
|
|
530
|
+
tick: int = 0
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
#: The freshly-seeded :class:`ConsoleState` a session opens with.
|
|
534
|
+
#:
|
|
535
|
+
#: A pure constant (no session data baked in) so the initial render is
|
|
536
|
+
#: deterministic and the store can be re-seeded without consulting any
|
|
537
|
+
#: runtime. Loaders overlay user preferences (scheme, toggles) on top of this
|
|
538
|
+
#: base via :func:`induscode.console.reducer.init_console_state`.
|
|
539
|
+
EMPTY_CONSOLE_STATE: Final[ConsoleState] = ConsoleState()
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
# ---------------------------------------------------------------------------
|
|
543
|
+
# The reducer event union
|
|
544
|
+
# ---------------------------------------------------------------------------
|
|
545
|
+
#
|
|
546
|
+
# The closed action union the console reducer folds over ConsoleState. The
|
|
547
|
+
# discriminants are the console's own ``domain:verb`` vocabulary, kept
|
|
548
|
+
# verbatim from TS. The TS composer families (``buffer:*``, ``caret:*``,
|
|
549
|
+
# ``history:*``) are dropped — the framework EditorCore owns those (port
|
|
550
|
+
# delta; see the module docstring). Grouped by the slice each touches:
|
|
551
|
+
#
|
|
552
|
+
# Transcript view
|
|
553
|
+
# - ``rows:set`` — replace the whole row list.
|
|
554
|
+
# - ``rows:append`` — append one row.
|
|
555
|
+
# - ``rows:patch`` — replace the text of the row matching an id.
|
|
556
|
+
# - ``block:append`` — append a display block.
|
|
557
|
+
# - ``blocks:clear`` — drop every display block (e.g. on a new session).
|
|
558
|
+
#
|
|
559
|
+
# Overlays, status, theme, toggles, busy
|
|
560
|
+
# - ``modal:open`` — raise an overlay (with optional payload).
|
|
561
|
+
# - ``modal:close`` — drop back to the composer.
|
|
562
|
+
# - ``status:set`` — show a transient status message.
|
|
563
|
+
# - ``status:clear`` — clear the status line.
|
|
564
|
+
# - ``scheme:set`` — switch the active colour scheme.
|
|
565
|
+
# - ``toggle:reasoning`` — flip reasoning-row visibility.
|
|
566
|
+
# - ``toggle:images`` — flip inline-image rendering.
|
|
567
|
+
# - ``busy:set`` — set the in-flight flag.
|
|
568
|
+
# - ``tick`` — bump the status-bar re-render tick.
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
@dataclass(frozen=True, slots=True)
|
|
572
|
+
class RowsSet:
|
|
573
|
+
"""Replace the whole row list."""
|
|
574
|
+
|
|
575
|
+
type: ClassVar[Literal["rows:set"]] = "rows:set"
|
|
576
|
+
rows: tuple[ViewRow, ...]
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
@dataclass(frozen=True, slots=True)
|
|
580
|
+
class RowsAppend:
|
|
581
|
+
"""Append one row."""
|
|
582
|
+
|
|
583
|
+
type: ClassVar[Literal["rows:append"]] = "rows:append"
|
|
584
|
+
row: ViewRow
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@dataclass(frozen=True, slots=True)
|
|
588
|
+
class RowsPatch:
|
|
589
|
+
"""Replace the text of the row matching ``id``."""
|
|
590
|
+
|
|
591
|
+
type: ClassVar[Literal["rows:patch"]] = "rows:patch"
|
|
592
|
+
id: str
|
|
593
|
+
text: str
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
@dataclass(frozen=True, slots=True)
|
|
597
|
+
class BlockAppend:
|
|
598
|
+
"""Append a display block."""
|
|
599
|
+
|
|
600
|
+
type: ClassVar[Literal["block:append"]] = "block:append"
|
|
601
|
+
block: UiDisplayBlock
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
@dataclass(frozen=True, slots=True)
|
|
605
|
+
class BlocksClear:
|
|
606
|
+
"""Drop every display block (e.g. on a new session)."""
|
|
607
|
+
|
|
608
|
+
type: ClassVar[Literal["blocks:clear"]] = "blocks:clear"
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
@dataclass(frozen=True, slots=True)
|
|
612
|
+
class ModalOpen:
|
|
613
|
+
"""Raise an overlay (with optional payload)."""
|
|
614
|
+
|
|
615
|
+
type: ClassVar[Literal["modal:open"]] = "modal:open"
|
|
616
|
+
kind: ModalKind
|
|
617
|
+
payload: object | None = None
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
@dataclass(frozen=True, slots=True)
|
|
621
|
+
class ModalClose:
|
|
622
|
+
"""Drop back to the composer."""
|
|
623
|
+
|
|
624
|
+
type: ClassVar[Literal["modal:close"]] = "modal:close"
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
@dataclass(frozen=True, slots=True)
|
|
628
|
+
class StatusSet:
|
|
629
|
+
"""Show a transient status message."""
|
|
630
|
+
|
|
631
|
+
type: ClassVar[Literal["status:set"]] = "status:set"
|
|
632
|
+
status: StatusMessage
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
@dataclass(frozen=True, slots=True)
|
|
636
|
+
class StatusClear:
|
|
637
|
+
"""Clear the status line."""
|
|
638
|
+
|
|
639
|
+
type: ClassVar[Literal["status:clear"]] = "status:clear"
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
@dataclass(frozen=True, slots=True)
|
|
643
|
+
class SchemeSet:
|
|
644
|
+
"""Switch the active colour scheme."""
|
|
645
|
+
|
|
646
|
+
type: ClassVar[Literal["scheme:set"]] = "scheme:set"
|
|
647
|
+
scheme: ThemeScheme
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
@dataclass(frozen=True, slots=True)
|
|
651
|
+
class ToggleReasoning:
|
|
652
|
+
"""Flip reasoning-row visibility."""
|
|
653
|
+
|
|
654
|
+
type: ClassVar[Literal["toggle:reasoning"]] = "toggle:reasoning"
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
@dataclass(frozen=True, slots=True)
|
|
658
|
+
class ToggleImages:
|
|
659
|
+
"""Flip inline-image rendering."""
|
|
660
|
+
|
|
661
|
+
type: ClassVar[Literal["toggle:images"]] = "toggle:images"
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
@dataclass(frozen=True, slots=True)
|
|
665
|
+
class BusySet:
|
|
666
|
+
"""Set the in-flight flag."""
|
|
667
|
+
|
|
668
|
+
type: ClassVar[Literal["busy:set"]] = "busy:set"
|
|
669
|
+
busy: bool
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
@dataclass(frozen=True, slots=True)
|
|
673
|
+
class Tick:
|
|
674
|
+
"""Bump the status-bar re-render tick."""
|
|
675
|
+
|
|
676
|
+
type: ClassVar[Literal["tick"]] = "tick"
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
#: The closed action union the console reducer folds over ConsoleState.
|
|
680
|
+
ConsoleEvent: TypeAlias = (
|
|
681
|
+
RowsSet
|
|
682
|
+
| RowsAppend
|
|
683
|
+
| RowsPatch
|
|
684
|
+
| BlockAppend
|
|
685
|
+
| BlocksClear
|
|
686
|
+
| ModalOpen
|
|
687
|
+
| ModalClose
|
|
688
|
+
| StatusSet
|
|
689
|
+
| StatusClear
|
|
690
|
+
| SchemeSet
|
|
691
|
+
| ToggleReasoning
|
|
692
|
+
| ToggleImages
|
|
693
|
+
| BusySet
|
|
694
|
+
| Tick
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
#: The discriminant literals of :data:`ConsoleEvent`, for filtering/logging.
|
|
698
|
+
ConsoleEventType: TypeAlias = Literal[
|
|
699
|
+
"rows:set",
|
|
700
|
+
"rows:append",
|
|
701
|
+
"rows:patch",
|
|
702
|
+
"block:append",
|
|
703
|
+
"blocks:clear",
|
|
704
|
+
"modal:open",
|
|
705
|
+
"modal:close",
|
|
706
|
+
"status:set",
|
|
707
|
+
"status:clear",
|
|
708
|
+
"scheme:set",
|
|
709
|
+
"toggle:reasoning",
|
|
710
|
+
"toggle:images",
|
|
711
|
+
"busy:set",
|
|
712
|
+
"tick",
|
|
713
|
+
]
|
|
714
|
+
|
|
715
|
+
#: Every event discriminant, in declaration order — the reducer key-coverage
|
|
716
|
+
#: test folds one event of each tag through the reducer (the Python analogue
|
|
717
|
+
#: of TS union exhaustiveness; cross-cutting rule 1).
|
|
718
|
+
CONSOLE_EVENT_TYPES: Final[tuple[ConsoleEventType, ...]] = (
|
|
719
|
+
"rows:set",
|
|
720
|
+
"rows:append",
|
|
721
|
+
"rows:patch",
|
|
722
|
+
"block:append",
|
|
723
|
+
"blocks:clear",
|
|
724
|
+
"modal:open",
|
|
725
|
+
"modal:close",
|
|
726
|
+
"status:set",
|
|
727
|
+
"status:clear",
|
|
728
|
+
"scheme:set",
|
|
729
|
+
"toggle:reasoning",
|
|
730
|
+
"toggle:images",
|
|
731
|
+
"busy:set",
|
|
732
|
+
"tick",
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
#: The reducer signature the console store is built from.
|
|
736
|
+
ConsoleReducer: TypeAlias = Callable[[ConsoleState, ConsoleEvent], ConsoleState]
|
|
737
|
+
|
|
738
|
+
#: The bound dispatch function the surface threads to its children.
|
|
739
|
+
ConsoleDispatch: TypeAlias = Callable[[ConsoleEvent], None]
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
# ---------------------------------------------------------------------------
|
|
743
|
+
# The console host props
|
|
744
|
+
# ---------------------------------------------------------------------------
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
class StartOAuthLogin(Protocol):
|
|
748
|
+
"""Drive a provider's browser sign-in and persist the result through the
|
|
749
|
+
vault: ``await start_oauth_login(provider_id, callbacks, vault, account)``.
|
|
750
|
+
"""
|
|
751
|
+
|
|
752
|
+
def __call__(
|
|
753
|
+
self,
|
|
754
|
+
provider_id: str,
|
|
755
|
+
callbacks: OAuthLoginCallbacks,
|
|
756
|
+
vault: AuthVault,
|
|
757
|
+
account: str | None = None,
|
|
758
|
+
) -> Awaitable[OAuthLoginResult]: ...
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
@dataclass(frozen=True, slots=True)
|
|
762
|
+
class OverlayServices:
|
|
763
|
+
"""The runtime handles the modal overlays reach for when they open.
|
|
764
|
+
|
|
765
|
+
The console surface itself stays UI-local — it knows nothing about
|
|
766
|
+
settings files, the session catalog, or the credential store. Each
|
|
767
|
+
overlay that needs to drive one of those is handed this bundle (threaded
|
|
768
|
+
through :attr:`ConsoleProps.services`), so a dialog body can read/write a
|
|
769
|
+
preference, list and open saved sessions, enumerate sign-in providers,
|
|
770
|
+
run a browser login, and persist credentials — all without prop-drilling
|
|
771
|
+
individual dependencies through the surface. It is optional on
|
|
772
|
+
:class:`ConsoleProps`: the headless and test mount paths run without it,
|
|
773
|
+
and an overlay group that finds it absent renders nothing.
|
|
774
|
+
"""
|
|
775
|
+
|
|
776
|
+
# The session this console drives (model selection, branching, forking).
|
|
777
|
+
conductor: SessionConductor
|
|
778
|
+
# The two-tier preference reader/writer behind the settings overlays.
|
|
779
|
+
settings: PreferenceStore
|
|
780
|
+
# The catalog-and-navigation layer over persisted transcripts.
|
|
781
|
+
sessions: SessionLibrary
|
|
782
|
+
# Enumerate the merged sign-in directory (browser + api-key providers).
|
|
783
|
+
list_login_providers: Callable[[], list[LoginProvider]]
|
|
784
|
+
# Drive a provider's browser sign-in and persist the result via the vault.
|
|
785
|
+
start_oauth_login: StartOAuthLogin
|
|
786
|
+
# Open a sign-in url in the user's browser (Chrome-first per platform).
|
|
787
|
+
# Resolves True when a browser was launched, False otherwise — the OAuth
|
|
788
|
+
# overlay calls this so the consent page opens automatically, matching
|
|
789
|
+
# the CLI sign-in path.
|
|
790
|
+
open_login_url: Callable[[str], Awaitable[bool]]
|
|
791
|
+
# The credential store sign-in / sign-out overlays read and write.
|
|
792
|
+
vault: AuthVault
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
@dataclass(frozen=True, slots=True)
|
|
796
|
+
class ConsoleProps:
|
|
797
|
+
"""What the root console surface receives at mount.
|
|
798
|
+
|
|
799
|
+
The console is a consumer: it is handed a fully-assembled
|
|
800
|
+
``SessionConductor`` to drive, the resolved :class:`ConsoleTheme` to
|
|
801
|
+
render in, the :class:`SlashRegistry` to dispatch against, and a small
|
|
802
|
+
set of optional seeds (a first message, preloaded images, a request-exit
|
|
803
|
+
hook). It owns no runtime of its own.
|
|
804
|
+
"""
|
|
805
|
+
|
|
806
|
+
# The session this console drives and renders.
|
|
807
|
+
conductor: SessionConductor
|
|
808
|
+
# The resolved colour scheme to render in.
|
|
809
|
+
theme: ConsoleTheme
|
|
810
|
+
# The slash-command registry the composer dispatches against.
|
|
811
|
+
slash: SlashRegistry
|
|
812
|
+
# An optional first user turn to submit on mount.
|
|
813
|
+
initial_input: str | None = None
|
|
814
|
+
# Optional local image paths to attach to the first turn.
|
|
815
|
+
initial_images: tuple[str, ...] = ()
|
|
816
|
+
# Whether to render verbose diagnostics in the banner.
|
|
817
|
+
verbose: bool = False
|
|
818
|
+
# Invoked when the console asks the host process to exit.
|
|
819
|
+
on_exit: Callable[[], None] | None = None
|
|
820
|
+
# The runtime handles the modal overlays drive; absent on headless paths.
|
|
821
|
+
services: OverlayServices | None = None
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
@dataclass(frozen=True, slots=True)
|
|
825
|
+
class ConsoleHost:
|
|
826
|
+
"""The ambient context the surface threads to its descendants.
|
|
827
|
+
|
|
828
|
+
A narrow read-only handle on the things deep children need without prop
|
|
829
|
+
drilling: the conductor to drive and the exit request. Larger state flows
|
|
830
|
+
through the reducer, not this object.
|
|
831
|
+
"""
|
|
832
|
+
|
|
833
|
+
# The session this console drives.
|
|
834
|
+
conductor: SessionConductor
|
|
835
|
+
# Ask the host process to exit the interactive console.
|
|
836
|
+
request_exit: Callable[[], None]
|