@xmoon76/dsh-pi-tui 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -198,16 +198,17 @@
198
198
  toolName: subagent_fork
199
199
  backgroundMode: continuable
200
200
 
201
- # Product providers are host-plane singletons. Copy this preset, then
202
- # remove `disabled` from either ordinary tool row to expose that product
203
- # only to agents composed from the copy.
201
+ # Production dsh does not install these optional providers. Install the
202
+ # matching Bundle in this Profile and restart the Host, then copy this
203
+ # preset and remove `disabled` from the matching tool row. Host availability
204
+ # alone grants no tool.
204
205
  - id: tool-subagent-codex
205
206
  name: '@deepseek-ai/dsh-tool-subagent'
206
207
  disabled: true
207
208
  config:
208
209
  provider: codex
209
210
  toolName: subagent_codex
210
- enableRunInBackground: false
211
+ backgroundMode: one-shot
211
212
  maxDepth: provider-managed
212
213
 
213
214
  - id: tool-subagent-claude-code
@@ -216,7 +217,7 @@
216
217
  config:
217
218
  provider: claude-code
218
219
  toolName: subagent_claude_code
219
- enableRunInBackground: false
220
+ backgroundMode: one-shot
220
221
  maxDepth: provider-managed
221
222
 
222
223
  - id: workflow-worker-thread
@@ -185,16 +185,17 @@
185
185
  toolName: subagent_fork
186
186
  backgroundMode: continuable
187
187
 
188
- # Product providers are host-plane singletons. Copy this preset, then
189
- # remove `disabled` from either ordinary tool row to expose that product
190
- # only to agents composed from the copy.
188
+ # Production dsh does not install these optional providers. Install the
189
+ # matching Bundle in this Profile and restart the Host, then copy this
190
+ # preset and remove `disabled` from the matching tool row. Host availability
191
+ # alone grants no tool.
191
192
  - id: tool-subagent-codex
192
193
  name: '@deepseek-ai/dsh-tool-subagent'
193
194
  disabled: true
194
195
  config:
195
196
  provider: codex
196
197
  toolName: subagent_codex
197
- enableRunInBackground: false
198
+ backgroundMode: one-shot
198
199
  maxDepth: provider-managed
199
200
 
200
201
  - id: tool-subagent-claude-code
@@ -203,7 +204,7 @@
203
204
  config:
204
205
  provider: claude-code
205
206
  toolName: subagent_claude_code
206
- enableRunInBackground: false
207
+ backgroundMode: one-shot
207
208
  maxDepth: provider-managed
208
209
 
209
210
  - id: workflow-worker-thread
@@ -134,7 +134,7 @@ Copy these disabled templates from a shipped full preset and remove `disabled` o
134
134
  config:
135
135
  provider: codex
136
136
  toolName: subagent_codex
137
- enableRunInBackground: false
137
+ backgroundMode: one-shot
138
138
  maxDepth: provider-managed
139
139
 
140
140
  - id: tool-subagent-claude-code
@@ -143,11 +143,11 @@ Copy these disabled templates from a shipped full preset and remove `disabled` o
143
143
  config:
144
144
  provider: claude-code
145
145
  toolName: subagent_claude_code
146
- enableRunInBackground: false
146
+ backgroundMode: one-shot
147
147
  maxDepth: provider-managed
148
148
  ```
149
149
 
150
- The two rows are independent. Leaving both disabled preserves the copied preset, enabling one exposes only that product tool, and enabling both exposes both. The host must provide `codex` or `claude` on `PATH`; the preset does not install, authenticate, select a model for, or probe either product.
150
+ The two rows are independent. Leaving both disabled preserves the copied preset, enabling one exposes only that product tool, and enabling both exposes both. Production `dsh` does not install either optional provider: before enabling a row, install the matching `@deepseek-ai/dsh-subagent-codex` or `@deepseek-ai/dsh-subagent-claude-code` Bundle in the Profile and restart it. Each Bundle registers its dormant default provider and exclusively uses its pinned package-local platform CLI; additional named instances use extra host-plane rows from the same installed package. A preset cannot provide that host dependency. `backgroundMode: one-shot` keeps omitted or `false` calls in the foreground and lets explicit `run_in_background: true` return a generic Job id. Full presets already carry `tool-jobs`, while the base host carries the job registry; retain both so `job_output`, `job_list`, `job_kill`, cancellation, and completion notices stay available. Installing a Bundle or composing a preset row does not start a product, authenticate an account, select a model, probe credentials, or manage native product settings.
151
151
 
152
152
  ## What not to move into a preset
153
153
 
@@ -3,7 +3,8 @@
3
3
  # The persona is the complete system prompt, so global identity, Web orientation,
4
4
  # tool guidance, and later assembly listeners cannot add prompt text. Runtime
5
5
  # context snapshots are suppressed for this preset, and the model composes only
6
- # persistent `bash` and `str_replace_editor`. Context compaction is absent.
6
+ # the persistent shell (`bash` on POSIX, `pwsh` on win32) and
7
+ # `str_replace_editor`. Context compaction is absent.
7
8
 
8
9
  - id: persona
9
10
  name: '@deepseek-ai/dsh-persona'
@@ -15,6 +16,8 @@
15
16
  # The PTY registry is an agent-owned service, so it lives in an entry-local
16
17
  # realm. The backend still consumes the host sandbox policy and subprocess
17
18
  # implementation, while the tool registers into this agent's scoped catalog.
19
+ # Exactly one shell stack mounts per host: the bash stack gates off win32 and
20
+ # its pwsh twin gates off POSIX, mirroring the one-shot shell rows.
18
21
  - id: persistent-shell
19
22
  name: cordis:group
20
23
  group: true
@@ -26,11 +29,13 @@
26
29
 
27
30
  - id: terminal-bash
28
31
  name: '@deepseek-ai/dsh-terminal-bash'
32
+ disabled: !!js process.platform === 'win32'
29
33
  config:
30
34
  timeoutMs: 300000
31
35
 
32
36
  - id: persistent-bash
33
37
  name: '@deepseek-ai/dsh-tool-bash-persistent'
38
+ disabled: !!js process.platform === 'win32'
34
39
  config:
35
40
  timeoutMs: 300000
36
41
  description: |-
@@ -43,6 +48,27 @@
43
48
  * Please avoid commands that may produce a very large amount of output.
44
49
  * Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.
45
50
 
51
+ - id: terminal-pwsh
52
+ name: '@deepseek-ai/dsh-terminal-bash'
53
+ disabled: !!js process.platform !== 'win32'
54
+ config:
55
+ shellDialect: pwsh
56
+ timeoutMs: 300000
57
+
58
+ - id: persistent-pwsh
59
+ name: '@deepseek-ai/dsh-tool-pwsh-persistent'
60
+ disabled: !!js process.platform !== 'win32'
61
+ config:
62
+ timeoutMs: 300000
63
+ description: |-
64
+ Run commands in a PowerShell shell
65
+ * When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
66
+ * You don't have access to the internet via this tool.
67
+ * State is persistent across command calls and discussions with the user.
68
+ * Use native Windows paths (C:\...) and $env:NAME variables; this is PowerShell, not bash.
69
+ * Please avoid commands that may produce a very large amount of output.
70
+ * Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.
71
+
46
72
  # The bare local filesystem shadows the host's sandboxed provider only for this
47
73
  # preset. The editor shares that realm and requires absolute paths.
48
74
  - id: filesystem
@@ -197,16 +197,17 @@
197
197
  toolName: subagent_fork
198
198
  backgroundMode: continuable
199
199
 
200
- # Product providers are host-plane singletons. Copy this preset, then
201
- # remove `disabled` from either ordinary tool row to expose that product
202
- # only to agents composed from the copy.
200
+ # Production dsh does not install these optional providers. Install the
201
+ # matching Bundle in this Profile and restart the Host, then copy this
202
+ # preset and remove `disabled` from the matching tool row. Host availability
203
+ # alone grants no tool.
203
204
  - id: tool-subagent-codex
204
205
  name: '@deepseek-ai/dsh-tool-subagent'
205
206
  disabled: true
206
207
  config:
207
208
  provider: codex
208
209
  toolName: subagent_codex
209
- enableRunInBackground: false
210
+ backgroundMode: one-shot
210
211
  maxDepth: provider-managed
211
212
 
212
213
  - id: tool-subagent-claude-code
@@ -215,7 +216,7 @@
215
216
  config:
216
217
  provider: claude-code
217
218
  toolName: subagent_claude_code
218
- enableRunInBackground: false
219
+ backgroundMode: one-shot
219
220
  maxDepth: provider-managed
220
221
 
221
222
  - id: workflow-worker-thread
package/cordis.patch.yml CHANGED
@@ -11,9 +11,22 @@
11
11
  - id: tui-startup
12
12
  name: '@xmoon76/dsh-pi-tui/startup'
13
13
 
14
+ # The extension platform (M3/E): the host provides the piTuiExtensions
15
+ # service (third-party plugins inject it), the builtins row registers
16
+ # the first-party chrome contributions through the SAME public API, and
17
+ # the runner row attaches the surface host over the service's ledger.
18
+ # All three gate on tuiStartup, so `--help` mounts none of them.
19
+ - id: pi-tui-extension-host
20
+ name: '@xmoon76/dsh-pi-tui/extensions'
21
+ inject: [tuiStartup]
22
+
23
+ - id: pi-tui-builtins
24
+ name: '@xmoon76/dsh-pi-tui/builtins'
25
+ inject: [tuiStartup, piTuiExtensions]
26
+
14
27
  - id: tui-app
15
28
  name: '@xmoon76/dsh-pi-tui'
16
- inject: [tuiStartup]
29
+ inject: [tuiStartup, piTuiExtensions]
17
30
  config:
18
31
  sessionId: ''
19
32
 
@@ -0,0 +1,18 @@
1
+ import { Context } from "@deepseek-ai/cordis";
2
+
3
+ //#region src/builtins.d.ts
4
+ /** Stable Cordis plugin name for the builtins row. */
5
+ declare const name = "pi-tui-builtins";
6
+ /** The builtins mount only when the TUI startup flags were parsed. */
7
+ declare const inject: string[];
8
+ /**
9
+ * Register the first-party chrome contributions. The turn/step footer
10
+ * segment subscribes to the surface state and re-bakes via handle.replace
11
+ * on every state change (the async-producer → cache → invalidate pattern
12
+ * from the plan §8.4, with replace() as the cache commit).
13
+ * @param ctx - the builtins plugin context (the extension service resolves
14
+ * through it; the registration is owned by THIS fiber).
15
+ */
16
+ declare function apply(ctx: Context): void;
17
+ //#endregion
18
+ export { apply, inject, name };
@@ -0,0 +1,75 @@
1
+ import { TUI_STARTUP_SERVICE } from "./startup.mjs";
2
+ import { M as PI_TUI_EXTENSIONS_SERVICE } from "./src-AgdnRnGA.mjs";
3
+ import { readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ //#region src/builtins.ts
6
+ /** Stable Cordis plugin name for the builtins row. */
7
+ const name = "pi-tui-builtins";
8
+ /** The builtins mount only when the TUI startup flags were parsed. */
9
+ const inject = [TUI_STARTUP_SERVICE, PI_TUI_EXTENSIONS_SERVICE];
10
+ /** The `@xmoon76/dsh-pi-tui` package version (dist/extensions.mjs → ../package.json). */
11
+ function packageVersion() {
12
+ try {
13
+ return JSON.parse(readFileSync(join(import.meta.dirname, "..", "package.json"), "utf8")).version ?? "0.0.0";
14
+ } catch {
15
+ return "0.0.0";
16
+ }
17
+ }
18
+ /**
19
+ * Register the first-party chrome contributions. The turn/step footer
20
+ * segment subscribes to the surface state and re-bakes via handle.replace
21
+ * on every state change (the async-producer → cache → invalidate pattern
22
+ * from the plan §8.4, with replace() as the cache commit).
23
+ * @param ctx - the builtins plugin context (the extension service resolves
24
+ * through it; the registration is owned by THIS fiber).
25
+ */
26
+ function apply(ctx) {
27
+ if (ctx.get("tuiStartup") === void 0) return;
28
+ const service = ctx.get(PI_TUI_EXTENSIONS_SERVICE);
29
+ if (service === void 0) return;
30
+ service.register("chrome.header.badge", {
31
+ id: "builtin-version",
32
+ order: 1e3,
33
+ description: "The bundle version (first-party builtin)."
34
+ }, {
35
+ text: `v${packageVersion()}`,
36
+ tone: "info"
37
+ });
38
+ const counters = service.register("chrome.footer.status", {
39
+ id: "builtin-turns-steps",
40
+ order: 1e3,
41
+ description: "Completed turns/steps counters (first-party builtin)."
42
+ }, { spans: [] });
43
+ const renderCounters = (state) => {
44
+ const spans = [{ text: `t${state.session.turns}/s${state.session.steps}` }];
45
+ counters.replace({ spans });
46
+ };
47
+ service.subscribeState((state) => {
48
+ renderCounters(state);
49
+ });
50
+ const todoDock = service.register("input.dock.item", {
51
+ id: "builtin-todo-summary",
52
+ order: 1e3,
53
+ description: "The todo summary line (first-party builtin)."
54
+ }, { label: [] });
55
+ const renderTodoDock = (state) => {
56
+ const summary = state.activity.todoSummary;
57
+ if (summary === void 0 || summary === "") {
58
+ todoDock.replace({ label: [] });
59
+ return;
60
+ }
61
+ const label = [{
62
+ text: "☑ ",
63
+ tone: "textDim"
64
+ }, {
65
+ text: summary,
66
+ tone: "textDim"
67
+ }];
68
+ todoDock.replace({ label });
69
+ };
70
+ service.subscribeState((state) => {
71
+ renderTodoDock(state);
72
+ });
73
+ }
74
+ //#endregion
75
+ export { apply, inject, name };
@@ -0,0 +1,372 @@
1
+ import { E as PiTuiApiInfo, T as NormalizedKey, _ as ExtensionTier, at as TuiOverlayOptions, h as EditorSnapshot, v as ExtensionView } from "../public-types-2omeXG8d.mjs";
2
+
3
+ //#region src/extension/advanced-types.d.ts
4
+ /** API level of the advanced tier. Bumped only on advanced breaking changes. */
5
+ declare const ADVANCED_API_LEVEL: 1;
6
+ /**
7
+ * A normalized input event — the ONLY input shape an advanced plugin ever
8
+ * sees. The Host has already decoded the terminal protocol (legacy + Kitty
9
+ * CSI-u + modifyOtherKeys encodings, bracketed paste, key release/repeat
10
+ * filtering), so an advanced plugin behaves identically on every terminal.
11
+ */
12
+ type AdvancedInputEvent = /** One key press, normalized to the semantic identity. */{
13
+ readonly kind: 'key';
14
+ readonly key: NormalizedKey;
15
+ } /** One plain printable character run (ordinary typing). */ | {
16
+ readonly kind: 'text';
17
+ readonly text: string;
18
+ } /** A paste burst (bracketed-paste or the host's paste heuristic). */ | {
19
+ readonly kind: 'paste';
20
+ readonly text: string;
21
+ };
22
+ /** The capture modes of a normalized input capture (plan §5). */
23
+ type AdvancedInputCaptureMode = 'observe' | 'capture' | 'exclusive';
24
+ /**
25
+ * One normalized input capture registration (plan §5). The capture is
26
+ * consulted by the Host AFTER its own capturing flows (questions, approvals,
27
+ * overlays) and reserved lifecycle keys, and BEFORE the editor and the
28
+ * Stable keybindings — so an advanced plugin can preempt ordinary editor and
29
+ * panel input, but never a Host question/approval, a Host overlay, or a
30
+ * Host fatal-recovery shortcut (session safety stays Host-owned).
31
+ *
32
+ * Modes:
33
+ * - `observe` — never consumes; the handler is a pure observer.
34
+ * - `capture` — may consume the event (return true).
35
+ * - `exclusive` — the SOLE capture consumer while live: capture-mode
36
+ * captures are not consulted (observers still run). A second exclusive
37
+ * registration is an explicit error, never a load-order winner.
38
+ *
39
+ * Ordering is deterministic: `priority` ASC, then `id` ASC. A throwing
40
+ * handler is isolated (health ledger) and FAILS OPEN — the event continues
41
+ * down the Host ladder, so a broken capture can never stall the TUI.
42
+ */
43
+ interface AdvancedInputCaptureSpec {
44
+ /** Stable diagnostic identity, unique per owner. */
45
+ readonly id: string;
46
+ /** Deterministic ordering: priority ASC, then id ASC. */
47
+ readonly priority?: number;
48
+ /** observe | capture | exclusive (default: capture). */
49
+ readonly mode?: AdvancedInputCaptureMode;
50
+ /** Optional gate: the capture is consulted only while this returns true.
51
+ * A throwing gate is treated as false (the capture is skipped). */
52
+ readonly when?: () => boolean;
53
+ /**
54
+ * The event handler. Return true to CONSUME the event (the Host does
55
+ * nothing further with it); return false/undefined to pass it on.
56
+ * A throwing handler is isolated and fails open.
57
+ */
58
+ handle(event: AdvancedInputEvent): boolean | void;
59
+ }
60
+ /** A live handle on one normalized input capture. */
61
+ interface AdvancedInputCaptureHandle {
62
+ readonly id: string;
63
+ /** Remove the capture. Idempotent; owner unload also disposes it. */
64
+ dispose(): void;
65
+ }
66
+ /**
67
+ * The render context handed to an interactive component's render() (plan
68
+ * §6). The plugin owns its state; the Host compiles the returned
69
+ * ExtensionView and owns layout, ANSI, width/wrapping and error isolation.
70
+ */
71
+ interface AdvancedRenderContext {
72
+ readonly surfaceId: string;
73
+ readonly generation: number;
74
+ /** The current terminal width in cells (re-read at every compile). */
75
+ readonly width: number;
76
+ /** The current terminal height in rows. */
77
+ readonly height: number;
78
+ /** Whether this component currently owns keyboard focus. */
79
+ readonly focused: boolean;
80
+ }
81
+ /**
82
+ * A focused interactive component (plan §6): plugin-owned interactive
83
+ * state rendered through the Host's component kit. The Host compiles
84
+ * render() output, normalizes input, leases focus and isolates every
85
+ * callback — the plugin never touches a private component, screen or
86
+ * terminal.
87
+ */
88
+ interface AdvancedInteractiveComponent {
89
+ /** Render the current state as a structured view (Host-compiled). */
90
+ render(ctx: AdvancedRenderContext): ExtensionView;
91
+ /**
92
+ * Receive a normalized input event while this component owns focus.
93
+ * Return true to consume; false/undefined passes the event on (the Host
94
+ * drops it — the focused component owns the seat). A throwing handler
95
+ * is isolated.
96
+ */
97
+ handleInput?(event: AdvancedInputEvent): boolean | void;
98
+ /** The component gained keyboard focus. */
99
+ onFocus?(): void;
100
+ /** The component lost keyboard focus. */
101
+ onBlur?(): void;
102
+ /** The component was disposed (overlay closed / surface died). */
103
+ dispose?(): void;
104
+ }
105
+ /**
106
+ * A Host-owned focus lease (plan §7). In Phase 2 the lease is delivered
107
+ * through the interactive overlay lease (the overlay IS the focused
108
+ * interactive surface); a stale lease (surface disposed, owner unloaded)
109
+ * is inert.
110
+ */
111
+ interface AdvancedFocusHandle {
112
+ /** Whether this lease currently holds focus. */
113
+ readonly active: boolean;
114
+ /** Request focus for the leased surface. */
115
+ focus(): void;
116
+ /** Release focus. */
117
+ blur(): void;
118
+ /** Release the lease (idempotent; owner unload also releases it). */
119
+ dispose(): void;
120
+ }
121
+ /**
122
+ * A live lease on one interactive managed overlay (plan §8). The plugin
123
+ * owns the component's state; the Host owns the physical screen mount,
124
+ * the overlay stack, focus, fullscreen migration and final teardown. The
125
+ * lease is caller-fiber-owned: owner unload closes the overlay, and a
126
+ * stale lease (surface disposed) is inert.
127
+ */
128
+ interface AdvancedOverlayLease {
129
+ /** The lease identity (stable diagnostic id). */
130
+ readonly id: string;
131
+ /** Whether the overlay is still mounted (false after close/dispose). */
132
+ readonly active: boolean;
133
+ /** Whether the overlay currently owns keyboard focus. */
134
+ readonly focused: boolean;
135
+ /** Request focus for the overlay (also shows it if hidden). */
136
+ focus(): void;
137
+ /** Release focus. */
138
+ blur(): void;
139
+ /** Recompile the component's render() output and repaint. */
140
+ invalidate(): void;
141
+ /** Close the overlay (idempotent; the surface's dispose also closes it). */
142
+ close(): void;
143
+ /** Temporarily hide (the lease stays live). */
144
+ hide(): void;
145
+ /** Show again after hide(). */
146
+ show(): void;
147
+ }
148
+ /**
149
+ * The advanced editor controls (plan §9): direct semantic editor actions
150
+ * through the Host's editor seat. The Host owns submission/session safety
151
+ * (dispatch('submit') stays the explicit action path); these controls only
152
+ * carry text/cursor/focus. A stale controls object (surface disposed) is
153
+ * inert.
154
+ */
155
+ interface AdvancedEditorControls {
156
+ /** The current immutable editor snapshot (text/cursor/focus). */
157
+ getEditorState(): EditorSnapshot;
158
+ /** Replace the draft wholesale. */
159
+ setEditorText(text: string): void;
160
+ /** Move the cursor to a flat offset within the draft. */
161
+ setEditorCursor(offset: number): void;
162
+ /** Insert text at the cursor (or at an explicit offset). */
163
+ insertEditorText(text: string, at?: number): void;
164
+ /** Paste text at the cursor (same insertion semantics as
165
+ * insertEditorText at the cursor — the Host owns paste protection). */
166
+ pasteToEditor(text: string): void;
167
+ /** Request keyboard focus for the editor seat. */
168
+ requestEditorFocus(): void;
169
+ }
170
+ /** The advanced input facade (plan §5). */
171
+ interface AdvancedInputFacade {
172
+ /**
173
+ * Register a normalized input capture. Caller-fiber-owned: owner unload
174
+ * removes it. A duplicate id or a second exclusive capture is an explicit
175
+ * error.
176
+ */
177
+ capture(spec: AdvancedInputCaptureSpec): AdvancedInputCaptureHandle;
178
+ }
179
+ /** One selectable row in the imperative select broker. */
180
+ interface AdvancedSelectItem {
181
+ readonly value: string;
182
+ readonly label: string;
183
+ readonly description?: string;
184
+ readonly group?: string;
185
+ }
186
+ /** Options for {@link AdvancedUiFacade.select}. */
187
+ interface AdvancedSelectOptions {
188
+ readonly items: readonly AdvancedSelectItem[];
189
+ readonly header?: string;
190
+ readonly enableSearch?: boolean;
191
+ readonly width?: number;
192
+ readonly maxHeight?: number;
193
+ /** Abort the prompt (the promise resolves undefined). */
194
+ readonly signal?: AbortSignal;
195
+ }
196
+ /** Options for {@link AdvancedUiFacade.confirm}. */
197
+ interface AdvancedConfirmOptions {
198
+ readonly question: string;
199
+ readonly detail?: string;
200
+ /** The approve option label (default 'Yes'). */
201
+ readonly approveLabel?: string;
202
+ /** The reject option label (default 'No'). */
203
+ readonly rejectLabel?: string;
204
+ /** Abort the prompt (the promise resolves false). */
205
+ readonly signal?: AbortSignal;
206
+ }
207
+ /** Options for {@link AdvancedUiFacade.input}. */
208
+ interface AdvancedInputOptions {
209
+ readonly question: string;
210
+ readonly detail?: string;
211
+ /** Abort the prompt (the promise resolves undefined). */
212
+ readonly signal?: AbortSignal;
213
+ }
214
+ /** Options for {@link AdvancedUiFacade.notify}. */
215
+ interface AdvancedNotifyOptions {
216
+ readonly type?: 'info' | 'error';
217
+ }
218
+ /**
219
+ * The public host facade handed to a {@link AdvancedUiFacade.custom}
220
+ * factory (plan §4B). The plugin builds an interactive component against
221
+ * this facade — never a private TUI object — and completes the custom()
222
+ * promise through `done`/`close`.
223
+ */
224
+ interface AdvancedCustomHost {
225
+ readonly surfaceId: string;
226
+ readonly generation: number;
227
+ readonly width: number;
228
+ readonly height: number;
229
+ /** Complete the custom() promise with a result (closes the surface). */
230
+ done(result?: unknown): void;
231
+ /** Cancel the custom() promise (resolves undefined; closes the surface). */
232
+ close(): void;
233
+ }
234
+ /** The advanced UI facade (plan §6/§8 + Phase 4 §4A/§4B). */
235
+ interface AdvancedUiFacade {
236
+ /**
237
+ * Open an interactive managed overlay hosting a focused interactive
238
+ * component. The Host mounts it through its overlay broker (modal
239
+ * stacking, focus, fullscreen migration, teardown) and returns a
240
+ * caller-fiber-owned lease. A throwing render/input/focus callback is
241
+ * isolated (health ledger).
242
+ */
243
+ showInteractiveOverlay(component: AdvancedInteractiveComponent, options?: TuiOverlayOptions): AdvancedOverlayLease;
244
+ /**
245
+ * Imperative selection (plan §4A): show a picker and resolve with the
246
+ * selected value, or undefined on cancel/abort. Caller-fiber-owned:
247
+ * owner unload aborts the prompt. Reuses the Host's picker overlay —
248
+ * no second modal manager.
249
+ */
250
+ select(options: AdvancedSelectOptions): Promise<string | undefined>;
251
+ /**
252
+ * Imperative confirmation (plan §4A): show a yes/no question and
253
+ * resolve with the choice; cancel/abort resolves false. Caller-fiber-
254
+ * owned: owner unload aborts the prompt. Reuses the Host's question
255
+ * flow.
256
+ */
257
+ confirm(options: AdvancedConfirmOptions): Promise<boolean>;
258
+ /**
259
+ * Imperative free-text input (plan §4A): show a question with a
260
+ * free-text row and resolve with the text, or undefined on
261
+ * cancel/abort. Caller-fiber-owned: owner unload aborts the prompt.
262
+ * Reuses the Host's question flow.
263
+ */
264
+ input(options: AdvancedInputOptions): Promise<string | undefined>;
265
+ /**
266
+ * Imperative notification (plan §4A): show a transient notice. Bounded,
267
+ * no raw ANSI, surface-detach safe, plugin-unload safe.
268
+ */
269
+ notify(message: string, options?: AdvancedNotifyOptions): void;
270
+ /**
271
+ * Custom interactive UI (plan §4B): mount a factory-built interactive
272
+ * component (fullscreen/panel/overlay) and resolve with the result the
273
+ * component reports through {@link AdvancedCustomHost.done}, or
274
+ * undefined on close/cancel. The factory receives ONLY the public host
275
+ * facade — never a private TUI object. Caller-fiber-owned: owner
276
+ * unload closes the surface and settles the promise.
277
+ */
278
+ custom(factory: (host: AdvancedCustomHost) => AdvancedInteractiveComponent, options?: TuiOverlayOptions): Promise<unknown>;
279
+ }
280
+ /**
281
+ * The advanced host-state facade (plan §4D): semantic Host UI state
282
+ * control — theme query/select, title override, working-indicator
283
+ * override and tool-expansion preference. The Host owns persistence and
284
+ * repaint; these are live overrides (a stale facade is inert).
285
+ */
286
+ interface AdvancedHostState {
287
+ /** The current theme id ('dark' | 'light' | 'custom'). */
288
+ getTheme(): string;
289
+ /** Apply a theme by id ('dark'/'light' or a registered plugin theme
290
+ * name). Unknown names are a no-op. */
291
+ setTheme(name: string): void;
292
+ /** Override the session title shown in the header (undefined clears). */
293
+ setTitle(title: string | undefined): void;
294
+ /** Override the working-indicator message (undefined clears). */
295
+ setWorkingMessage(message: string | undefined): void;
296
+ /** Set the tool-output expansion master switch. */
297
+ setToolsExpanded(expanded: boolean): void;
298
+ }
299
+ /** The full advanced facade (plan §4: `advanced(service)`). */
300
+ interface AdvancedFacade {
301
+ /** Normalized input capture. */
302
+ readonly input: AdvancedInputFacade;
303
+ /** Focused interactive surfaces (interactive overlays) + the Phase-4
304
+ * imperative UI broker (select/confirm/input/notify/custom). */
305
+ readonly ui: AdvancedUiFacade;
306
+ /** The CURRENT surface's advanced editor controls (a getter — the
307
+ * controls follow the live surface attachment). */
308
+ readonly editor: AdvancedEditorControls;
309
+ /** The Phase-4 host-state facade (theme/title/working/tools-expanded). */
310
+ readonly host: AdvancedHostState;
311
+ }
312
+ /**
313
+ * The minimal service surface the advanced facade consumes (plan §4:
314
+ * `advanced(service)`). STRUCTURAL and defined here so the packed
315
+ * advanced declarations never reference the internal service module —
316
+ * the concrete `piTuiExtensions` service implements these members, but
317
+ * the public `PiTuiExtensionService` interface does not declare them.
318
+ *
319
+ * `api` is the structural anchor: a plain `PiTuiExtensionService` value
320
+ * satisfies the facade's parameter (the seam members are optional in the
321
+ * type), and the facade throws loudly when the host does not implement
322
+ * the seam (a host/plugin version mismatch) instead of failing later
323
+ * with an obscure "not a function".
324
+ */
325
+ interface AdvancedServiceHost {
326
+ /** The public api() surface (the structural anchor — the facade does
327
+ * not consume it; it makes a plain `PiTuiExtensionService` value
328
+ * assignable to the parameter). */
329
+ readonly api: () => PiTuiApiInfo;
330
+ /** The service's internal advanced seam: register a normalized input
331
+ * capture (caller-fiber-owned). */
332
+ _advancedCaptureInput?(spec: AdvancedInputCaptureSpec): AdvancedInputCaptureHandle;
333
+ /** The service's internal advanced seam: open an interactive managed
334
+ * overlay (caller-fiber-owned lease). */
335
+ _advancedShowInteractiveOverlay?(component: AdvancedInteractiveComponent, options?: TuiOverlayOptions): AdvancedOverlayLease;
336
+ /** The service's internal advanced seam: the current surface's advanced
337
+ * editor controls (inert when stale). */
338
+ _advancedEditorControls?(): AdvancedEditorControls;
339
+ /** The service's internal advanced seam (Phase 4): the imperative UI
340
+ * broker (select/confirm/input/notify/custom). */
341
+ _advancedUiSelect?(options: AdvancedSelectOptions): Promise<string | undefined>;
342
+ _advancedUiConfirm?(options: AdvancedConfirmOptions): Promise<boolean>;
343
+ _advancedUiInput?(options: AdvancedInputOptions): Promise<string | undefined>;
344
+ _advancedUiNotify?(message: string, options?: AdvancedNotifyOptions): void;
345
+ _advancedUiCustom?(factory: (host: AdvancedCustomHost) => AdvancedInteractiveComponent, options?: TuiOverlayOptions): Promise<unknown>;
346
+ /** The service's internal advanced seam (Phase 4): the host-state
347
+ * facade (theme/title/working/tools-expanded). */
348
+ _advancedHostState?(): AdvancedHostState;
349
+ }
350
+ //#endregion
351
+ //#region src/extension/advanced.d.ts
352
+ /**
353
+ * Build the ADVANCED facade over the shared `piTuiExtensions` service
354
+ * (plan §4). The facade is a thin capability view: every resource it
355
+ * creates is caller-fiber-owned and surface-generation-scoped through the
356
+ * service's shared Extension Runtime — never a second plugin system.
357
+ *
358
+ * The facade is safe to call before any surface exists: registrations
359
+ * (input captures) are service-lifetime and attach later; leases
360
+ * (interactive overlays) and the editor controls are inert until a
361
+ * surface is live.
362
+ *
363
+ * The parameter is the structural {@link AdvancedServiceHost}: a plain
364
+ * `PiTuiExtensionService` value is accepted (the seam members are optional
365
+ * in the type), and the facade throws loudly when the host does not
366
+ * implement the seam (a host/plugin version mismatch).
367
+ * @param service - the `piTuiExtensions` service (from `ctx.get(...)`).
368
+ * @returns the Advanced facade.
369
+ */
370
+ declare function advanced(service: AdvancedServiceHost): AdvancedFacade;
371
+ //#endregion
372
+ export { ADVANCED_API_LEVEL, type AdvancedConfirmOptions, type AdvancedCustomHost, type AdvancedEditorControls, type AdvancedFacade, type AdvancedFocusHandle, type AdvancedHostState, type AdvancedInputCaptureHandle, type AdvancedInputCaptureMode, type AdvancedInputCaptureSpec, type AdvancedInputEvent, type AdvancedInputFacade, type AdvancedInputOptions, type AdvancedInteractiveComponent, type AdvancedNotifyOptions, type AdvancedOverlayLease, type AdvancedRenderContext, type AdvancedSelectItem, type AdvancedSelectOptions, type AdvancedServiceHost, type AdvancedUiFacade, type ExtensionTier, advanced };