@timurproko/a1 0.2.6-dev.727 → 0.2.6-dev.734

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 (104) hide show
  1. package/dist/app/session-shell/clipboard-services.d.ts +19 -0
  2. package/dist/app/session-shell/clipboard-services.js +7 -0
  3. package/dist/app/session-shell/exit-notice.d.ts +9 -5
  4. package/dist/app/session-shell/exit-notice.js +5 -5
  5. package/dist/app/session-shell/index.d.ts +3 -1
  6. package/dist/app/session-shell/index.js +1 -0
  7. package/dist/app/session-shell/paste-preparation-client.d.ts +3 -0
  8. package/dist/app/session-shell/paste-preparation-client.js +5 -2
  9. package/dist/app/session-shell/path-chip-presentation.d.ts +10 -3
  10. package/dist/app/session-shell/path-chip-presentation.js +48 -6
  11. package/dist/app/session-shell/prompt-chips.js +30 -4
  12. package/dist/app/session-shell/quit-outro.d.ts +3 -1
  13. package/dist/app/session-shell/quit-outro.js +23 -8
  14. package/dist/app/session-shell/response-copy-transport.d.ts +6 -1
  15. package/dist/app/session-shell/response-copy-transport.js +8 -2
  16. package/dist/app/session-shell/session-shell-root.d.ts +20 -10
  17. package/dist/app/session-shell/session-shell-root.js +6 -6
  18. package/dist/app/session-shell/session-shell.d.ts +19 -21
  19. package/dist/app/session-shell/session-shell.js +656 -860
  20. package/dist/composition/owned-ui.d.ts +20 -2
  21. package/dist/composition/owned-ui.js +66 -35
  22. package/dist/composition/session-info-reference.d.ts +2 -2
  23. package/dist/composition/session-info-reference.js +2 -2
  24. package/dist/contracts/agent-engine/capability-ports.d.ts +1 -85
  25. package/dist/contracts/agent-engine/capability-ports.js +1 -35
  26. package/dist/contracts/agent-engine/index.d.ts +1 -7
  27. package/dist/contracts/agent-engine/index.js +0 -4
  28. package/dist/contracts/owned-ui/index.d.ts +5 -1
  29. package/dist/contracts/owned-ui/index.js +1 -0
  30. package/dist/contracts/owned-ui/model.d.ts +6 -0
  31. package/dist/contracts/owned-ui/session-backend.d.ts +119 -0
  32. package/dist/contracts/owned-ui/session-presenters.d.ts +55 -0
  33. package/dist/contracts/owned-ui/session-presenters.js +1 -0
  34. package/dist/contracts/owned-ui/session-workflows.d.ts +342 -0
  35. package/dist/contracts/owned-ui/session-workflows.js +30 -0
  36. package/dist/features/owned-ui/settings-app.js +35 -15
  37. package/dist/foundation/release/bootstrap.js +1 -2
  38. package/dist/foundation/release/release-gc.js +1 -1
  39. package/dist/foundation/release/update.js +0 -4
  40. package/dist/foundation/storage/control-store.js +0 -12
  41. package/dist/integrations/pi/components/components.js +0 -16
  42. package/dist/integrations/pi/components/index.d.ts +3 -3
  43. package/dist/integrations/pi/components/index.js +2 -2
  44. package/dist/integrations/pi/components/models-dialog.js +1 -30
  45. package/dist/integrations/pi/components/shell-editor-autocomplete.js +11 -9
  46. package/dist/integrations/pi/components/shell-extension-ui.d.ts +3 -3
  47. package/dist/integrations/pi/components/shell-extension-ui.js +6 -2
  48. package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -4
  49. package/dist/integrations/pi/components/shell-shared-facade.d.ts +21 -1
  50. package/dist/integrations/pi/components/shell-shared-facade.js +18 -2
  51. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +5 -1
  52. package/dist/integrations/pi/components/upstream/theme/theme.js +20 -2
  53. package/dist/integrations/pi/engine/adapter.d.ts +44 -24
  54. package/dist/integrations/pi/engine/adapter.js +130 -22
  55. package/dist/integrations/pi/engine/command-dispatch.d.ts +2 -5
  56. package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -11
  57. package/dist/integrations/pi/engine/host-ports.d.ts +20 -0
  58. package/dist/integrations/pi/engine/host-ports.js +13 -0
  59. package/dist/integrations/pi/engine/host.d.ts +70 -0
  60. package/dist/integrations/pi/engine/host.js +147 -0
  61. package/dist/integrations/pi/engine/index.d.ts +8 -4
  62. package/dist/integrations/pi/engine/index.js +3 -1
  63. package/dist/integrations/pi/engine/resource-catalog.d.ts +4 -23
  64. package/dist/integrations/pi/engine/runtime-integration.d.ts +8 -2
  65. package/dist/integrations/pi/engine/runtime-integration.js +12 -7
  66. package/dist/integrations/pi/engine/session-integration.d.ts +3 -8
  67. package/dist/integrations/pi/engine/session-integration.js +0 -49
  68. package/dist/integrations/pi/engine/session-runtime.d.ts +18 -3
  69. package/dist/integrations/pi/engine/session-runtime.js +18 -7
  70. package/dist/integrations/pi/engine/settings-bridge.d.ts +2 -2
  71. package/dist/integrations/pi/engine/settings-bridge.js +0 -2
  72. package/dist/integrations/pi/engine/settings-port.d.ts +2 -0
  73. package/dist/integrations/pi/engine/settings-port.js +3 -5
  74. package/dist/integrations/pi/engine/workflows.d.ts +33 -260
  75. package/dist/integrations/pi/engine/workflows.js +6 -28
  76. package/dist/integrations/pi/session-presenters/index.d.ts +2 -0
  77. package/dist/integrations/pi/session-presenters/index.js +1 -0
  78. package/dist/integrations/pi/session-presenters/presenters.d.ts +16 -0
  79. package/dist/integrations/pi/session-presenters/presenters.js +341 -0
  80. package/dist/integrations/pi/tui-runtime/adapter.js +0 -2
  81. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +7 -0
  82. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +66 -1
  83. package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
  84. package/dist/integrations/pi/tui-runtime/index.js +1 -1
  85. package/dist/native/darwin-arm64/manifest.json +1 -1
  86. package/dist/native/linux-x64/manifest.json +1 -1
  87. package/dist/native/win32-x64/manifest.json +2 -2
  88. package/dist/native/win32-x64/process-guardian.exe +0 -0
  89. package/dist/ui/settings/declarations.d.ts +13 -1
  90. package/dist/ui/settings/declarations.js +12 -1
  91. package/dist/ui/settings/migrations.js +7 -0
  92. package/docs/architecture/boundaries.md +9 -1
  93. package/docs/architecture/project-structure.md +3 -2
  94. package/package.json +1 -1
  95. package/dist/contracts/agent-engine/model.d.ts +0 -78
  96. package/dist/contracts/agent-engine/model.js +0 -1
  97. package/dist/contracts/agent-engine/ports.d.ts +0 -18
  98. package/dist/contracts/agent-engine/serialization.d.ts +0 -7
  99. package/dist/contracts/agent-engine/serialization.js +0 -58
  100. package/dist/contracts/agent-engine/validation.d.ts +0 -5
  101. package/dist/contracts/agent-engine/validation.js +0 -128
  102. package/dist/integrations/pi/components/upstream/theme/system-theme.d.ts +0 -61
  103. package/dist/integrations/pi/components/upstream/theme/system-theme.js +0 -709
  104. /package/dist/contracts/{agent-engine/ports.js → owned-ui/session-backend.js} +0 -0
@@ -1,16 +1,34 @@
1
1
  import type { AvailableRelease, StartupReleaseCheckOptions } from "../foundation/release/latest-release.js";
2
2
  import type { NativeProcessIdentity } from "../foundation/lifecycle/model.js";
3
3
  import type { SessionSelection } from "../foundation/lifecycle/session-selection.js";
4
- import type { PiEngineAdapter } from "../integrations/pi/engine/adapter.js";
4
+ import { type PiEngineHostOptions, type PiEngineSessionRequest } from "../integrations/pi/engine/host.js";
5
+ import { type PiSessionPresenterBackend } from "../integrations/pi/session-presenters/index.js";
5
6
  import type { PiProjectTrustPreflightPrompt } from "../integrations/pi/engine/project-trust-preflight.js";
6
7
  import type { PiSessionForkPrompt } from "../integrations/pi/engine/session-selection.js";
7
8
  import { OwnedSettingsManager } from "../ui/settings/manager.js";
8
9
  import type { OwnedUiApplicationPort, PresentationTerminalPort } from "../contracts/presentation/index.js";
10
+ import type { AgentSettingsPort } from "../contracts/agent-engine/index.js";
11
+ import type { OwnedUiPromptSuggestionGeneratorPort, UiAccentColor } from "../contracts/owned-ui/index.js";
9
12
  import type { ReleaseNoteCatalog } from "../features/owned-ui/release-notes.js";
13
+ /**
14
+ * The session backend composition wires: the owned-UI port, the prompt-suggestion generator, and
15
+ * the agent settings port. `settingsPort` stays outside the owned-UI contract because its type
16
+ * belongs to the agent-engine contracts, which the owned-UI contract may not import.
17
+ */
18
+ export interface ComposedSessionBackend extends PiSessionPresenterBackend, OwnedUiPromptSuggestionGeneratorPort {
19
+ settingsPort(): AgentSettingsPort | null;
20
+ }
21
+ /** The process-level engine host as composition drives it: sessions, the live accent, and disposal. */
22
+ export interface ComposedEngineHost {
23
+ create(request: PiEngineSessionRequest): Promise<ComposedSessionBackend>;
24
+ setAccentColor(color: UiAccentColor): void;
25
+ dispose(): Promise<void>;
26
+ }
10
27
  export interface OwnedUiCompositionOptions {
11
28
  readonly cwd?: string;
12
29
  readonly terminal?: PresentationTerminalPort;
13
- readonly createPiAdapter?: () => Promise<PiEngineAdapter>;
30
+ /** Test seam standing in for the Pi engine host; receives the options composition resolved. */
31
+ readonly createEngineHost?: (options: PiEngineHostOptions) => Promise<ComposedEngineHost>;
14
32
  /** Explicit file selection retained for SDK callers. Public CLI uses sessionSelection. */
15
33
  readonly sessionPath?: string;
16
34
  readonly sessionSelection?: SessionSelection;
@@ -7,8 +7,11 @@ import { resolvePromptHistoryPath } from "../features/prompt-history/paths.js";
7
7
  import { resolvePromptHistoryDataDir } from "../features/launch/profile-paths.js";
8
8
  import { resolveProductPaths } from "../foundation/lifecycle/paths.js";
9
9
  import { applyConfiguredPiTheme, getAvailablePiThemes, setPiAccentColor, setPiPackageBorderProjectionEnabled } from "../integrations/pi/components/upstream/theme/theme.js";
10
- import { createPiEngineAdapter } from "../integrations/pi/engine/adapter.js";
10
+ import { createPiEngineHost } from "../integrations/pi/engine/host.js";
11
+ import { createPiSessionPresenters } from "../integrations/pi/session-presenters/index.js";
11
12
  import { ClipboardDiagnosticCapture } from "../app/session-shell/clipboard-diagnostics.js";
13
+ import { createOwnedUiClipboardServices } from "../app/session-shell/clipboard-services.js";
14
+ import { createPiKeybindingsHost } from "../integrations/pi/components/shell-shared-facade.js";
12
15
  import { OwnedUiSessionShell } from "../app/session-shell/session-shell.js";
13
16
  import { OwnedSettingsManager } from "../ui/settings/manager.js";
14
17
  import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/presentation-adapter.js";
@@ -55,13 +58,35 @@ export async function composeOwnedUi(options = {}) {
55
58
  sessionRuntimeRefreshTimer = setInterval(queueSessionRuntimeRefresh, SESSION_RUNTIME_REFRESH_MS);
56
59
  sessionRuntimeRefreshTimer.unref();
57
60
  };
58
- const adapter = options.createPiAdapter
59
- ? await options.createPiAdapter()
60
- : await createPiEngineAdapter({
61
+ const productPaths = resolveProductPaths();
62
+ // Rationale: the manager reads the engine's settings port lazily, after the session exists.
63
+ let backend;
64
+ const settings = options.profileId === undefined
65
+ ? null
66
+ : new OwnedSettingsManager({
67
+ configDir: resolveProductPaths().configDir,
68
+ profileId: options.profileId,
69
+ agentProvider: () => backend.settingsPort(),
70
+ hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
71
+ agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
72
+ });
73
+ // Invariant: process-wide engine state has one owner. The host installs the HTTP dispatcher, applies
74
+ // the theme singletons, and announces startup notices once; every session is created through it.
75
+ const host = await (options.createEngineHost ?? (async (hostOptions) => createPiEngineHost(hostOptions)))({
76
+ productMode: ownedSurfaces ? "bare" : "comparison",
77
+ availableThemes: () => getAvailablePiThemes().map(theme => theme.name),
78
+ announceStartupChangelog: !ownedSurfaces,
79
+ theme: {
80
+ base: ownedSurfaces ? "dark" : "engine-configured",
81
+ accentColor: settings !== null && ownedSurfaces ? settings.value("accentColor") : "purple",
82
+ packageBorderProjection: ownedSurfaces,
83
+ apply: { base: applyConfiguredPiTheme, accentColor: setPiAccentColor, packageBorderProjection: setPiPackageBorderProjectionEnabled },
84
+ },
85
+ ...(options.projectTrustPrompt === undefined ? {} : { projectTrustPrompt: options.projectTrustPrompt }),
86
+ });
87
+ try {
88
+ backend = await host.create({
61
89
  cwd,
62
- availableThemes: () => getAvailablePiThemes().map(theme => theme.name),
63
- settingsProductMode: ownedSurfaces ? "bare" : "comparison",
64
- announceStartupChangelog: !ownedSurfaces,
65
90
  ...(ownedSurfaces ? {
66
91
  repositoryContextReader: async (sessionId, sessionFile, signal) => {
67
92
  const owner = await runtimeIdentity();
@@ -77,18 +102,12 @@ export async function composeOwnedUi(options = {}) {
77
102
  ...(options.sessionPath === undefined ? {} : { sessionPath: options.sessionPath }),
78
103
  ...(options.sessionSelection === undefined ? {} : { sessionSelection: options.sessionSelection }),
79
104
  ...(options.sessionForkPrompt === undefined ? {} : { sessionForkPrompt: options.sessionForkPrompt }),
80
- ...(options.projectTrustPrompt === undefined ? {} : { projectTrustPrompt: options.projectTrustPrompt }),
81
- });
82
- const productPaths = resolveProductPaths();
83
- const settings = options.profileId === undefined
84
- ? null
85
- : new OwnedSettingsManager({
86
- configDir: resolveProductPaths().configDir,
87
- profileId: options.profileId,
88
- agentProvider: () => adapter.settingsPort(),
89
- hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
90
- agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
91
105
  });
106
+ }
107
+ catch (error) {
108
+ await host.dispose();
109
+ throw error;
110
+ }
92
111
  let releaseNotes = null;
93
112
  let releaseNotesFailure;
94
113
  if (ownedSurfaces) {
@@ -109,15 +128,9 @@ export async function composeOwnedUi(options = {}) {
109
128
  : await import("../features/owned-ui/release-note-state.js").then(module => module.claimReleaseNote({
110
129
  configDir: productPaths.configDir, profileId: options.profileId, version: currentReleaseNote.version,
111
130
  }));
112
- // Compatibility: bare A1 intentionally ships one base visual target while its UI is being completed:
113
- // dark, regardless of terminal detection or a previously stored Pi theme. Its owned accent projects
114
- // over that base; comparison keeps Pi's configured theme and unmodified semantic accent.
115
- setPiPackageBorderProjectionEnabled(ownedSurfaces);
116
- setPiAccentColor(settings !== null && ownedSurfaces ? settings.value("accentColor") : "purple");
117
- applyConfiguredPiTheme(ownedSurfaces ? "dark" : adapter.configuredTheme());
118
131
  const unsubscribeAccent = settings === null || !ownedSurfaces
119
132
  ? () => { }
120
- : settings.onChange(current => setPiAccentColor(current.value("accentColor")));
133
+ : settings.onChange(current => host.setAccentColor(current.value("accentColor")));
121
134
  // Rationale: Routes open only after shell construction.
122
135
  const references = {
123
136
  changelog: async (input) => {
@@ -131,19 +144,24 @@ export async function composeOwnedUi(options = {}) {
131
144
  const { renderPiShellHotkeySections } = await import("../integrations/pi/components/shell-hotkey-sections.js");
132
145
  return { sections: width => renderPiShellHotkeySections(presentation, width) };
133
146
  },
134
- session: () => import("./session-info-reference.js").then(m => m.loadSessionInfoReference(adapter)),
147
+ session: () => import("./session-info-reference.js").then(m => m.loadSessionInfoReference(backend)),
135
148
  };
136
149
  const routeHost = settings === null || !ownedSurfaces ? null : createOwnedRouteHost(settings, references);
137
150
  const viewportSettings = settings === null || !ownedSurfaces ? null : {
138
151
  snapshot: () => viewportSettingsSnapshot(settings),
139
152
  onChange: listener => settings.onChange(() => listener(viewportSettingsSnapshot(settings))),
140
153
  };
154
+ const backgroundSettings = settings === null || !ownedSurfaces ? null : {
155
+ snapshot: () => settings.value("backgroundStyle"),
156
+ // Rationale: one manager notification also recomputes an accent-derived canvas after accentColor changes.
157
+ onChange: listener => settings.onChange(current => listener(current.value("backgroundStyle"))),
158
+ };
141
159
  const diagnosticDestination = options.suggestionDiagnosticsPath ?? process.env[PRODUCT_IDENTITY.environment.suggestionDiagnostics];
142
160
  const suggestionDiagnostics = settings !== null && ownedSurfaces && diagnosticDestination?.trim()
143
161
  ? new SuggestionDiagnosticCapture({ enabled: true, destination: diagnosticDestination }) : null;
144
162
  const promptSuggestions = settings === null || !ownedSurfaces ? null : {
145
163
  ...(suggestionDiagnostics === null ? {} : { diagnostics: suggestionDiagnostics }),
146
- generator: adapter,
164
+ generator: backend,
147
165
  enabled: () => settings.value("promptSuggestions"),
148
166
  onChange: (listener) => settings.onChange(() => listener(settings.value("promptSuggestions"))),
149
167
  };
@@ -159,12 +177,12 @@ export async function composeOwnedUi(options = {}) {
159
177
  const historyLimit = settings?.value("promptHistoryMaxItems");
160
178
  const historyProfileLocation = settings === null || !ownedSurfaces || !settings.value("promptHistoryEnabled")
161
179
  ? null
162
- : resolvePromptHistoryPath(resolvePromptHistoryDataDir(), adapter.agentDir);
180
+ : resolvePromptHistoryPath(resolvePromptHistoryDataDir(), backend.identity.agentDir);
163
181
  const promptHistory = historyProfileLocation === null ? null : {
164
182
  limit: typeof historyLimit === "number" ? historyLimit : 100,
165
183
  store: new PromptHistoryService({
166
184
  dataDir: resolvePromptHistoryDataDir(),
167
- profileRoot: adapter.agentDir,
185
+ profileRoot: backend.identity.agentDir,
168
186
  limit: typeof historyLimit === "number" ? historyLimit : 100,
169
187
  }),
170
188
  imageSidecar: new PromptImageSidecar(historyProfileLocation.imagesDir),
@@ -172,13 +190,18 @@ export async function composeOwnedUi(options = {}) {
172
190
  const clipboardDestination = options.clipboardDiagnosticsPath ?? process.env[PRODUCT_IDENTITY.environment.clipboardDiagnostics];
173
191
  const clipboardDiagnostics = settings !== null && ownedSurfaces && clipboardDestination?.trim()
174
192
  ? new ClipboardDiagnosticCapture(clipboardDestination) : null;
193
+ // Invariant: process-wide services are created once here and borrowed by every session shell. The
194
+ // keybinding registry is applied before any presenter is built, so none of them reads Pi's defaults.
195
+ const keybindings = createPiKeybindingsHost({ profile: ownedSurfaces ? "a1" : "pi", agentDir: backend.identity.agentDir });
196
+ const clipboardServices = ownedSurfaces ? createOwnedUiClipboardServices() : null;
175
197
  let shell;
176
198
  let releaseNoteAcknowledgement = null;
177
199
  try {
178
200
  shell = new OwnedUiSessionShell({
201
+ presenters: createPiSessionPresenters(backend),
179
202
  engine: {
180
- backend: adapter,
181
- cwd: adapter.cwd,
203
+ backend,
204
+ cwd: backend.identity.cwd,
182
205
  ...(routeHost === null ? {} : { routeHost }),
183
206
  ...(currentReleaseNote === null || releaseNoteClaim === null ? {} : {
184
207
  startupRoute: {
@@ -196,6 +219,7 @@ export async function composeOwnedUi(options = {}) {
196
219
  ...(options.terminal === undefined ? {} : { terminal: createPiTerminalBridge(options.terminal) }),
197
220
  ...(clipboardDiagnostics === null ? {} : { input: { onEvent: event => clipboardDiagnostics.runtime(event) } }),
198
221
  ...(viewportSettings === null ? {} : { viewportSettings }),
222
+ ...(backgroundSettings === null ? {} : { backgroundSettings }),
199
223
  ...(settings === null || !ownedSurfaces ? {} : {
200
224
  quitOutro: { snapshot: () => quitOutroSettingsSnapshot(settings), interactive: process.stdout.isTTY === true },
201
225
  }),
@@ -207,6 +231,7 @@ export async function composeOwnedUi(options = {}) {
207
231
  ...(promptSuggestions === null ? {} : { suggestions: promptSuggestions }),
208
232
  ...(promptImages === null ? {} : { promptImages }),
209
233
  ...(skills === null ? {} : { skills }),
234
+ shared: { keybindings, ...(clipboardServices === null ? {} : { clipboard: clipboardServices }) },
210
235
  ...(promptHistory === null ? {} : { history: {
211
236
  ...promptHistory,
212
237
  editor: await import("../integrations/pi/components/history-editor-loader.js").then(module => module.loadHistoryEditor()),
@@ -218,6 +243,8 @@ export async function composeOwnedUi(options = {}) {
218
243
  await releaseNoteClaim?.release();
219
244
  clipboardDiagnostics?.dispose();
220
245
  suggestionDiagnostics?.dispose();
246
+ clipboardServices?.dispose();
247
+ await host.dispose();
221
248
  throw error;
222
249
  }
223
250
  // Rationale: pinned Pi's version check is unreachable because the owned shell never runs its
@@ -233,23 +260,23 @@ export async function composeOwnedUi(options = {}) {
233
260
  ...(settings === null || !ownedSurfaces ? {} : { settingEnabled: settings.value("updateCheck") }),
234
261
  });
235
262
  if (release !== null)
236
- adapter.announceReleaseUpdate(release);
263
+ backend.extensions.announceReleaseUpdate(release);
237
264
  };
238
265
  const exitNoticePath = process.env[PRODUCT_IDENTITY.environment.exitNoticePath];
239
266
  // Security: tools the agent runs must never see, or rewrite, this instance's notice.
240
267
  delete process.env[PRODUCT_IDENTITY.environment.exitNoticePath];
241
268
  let exitNotice = Promise.resolve(null);
242
269
  const application = {
243
- get disposed() { return adapter.disposed; },
270
+ get disposed() { return backend.identity.disposed; },
244
271
  start: () => {
245
272
  // Performance: the guardian notice loads beside first paint, never on the startup path.
246
273
  if (exitNoticePath)
247
274
  exitNotice = import("../app/session-shell/exit-notice.js")
248
- .then(module => module.armExitNotice(adapter, exitNoticePath), () => null);
275
+ .then(module => module.armExitNotice(backend, exitNoticePath), () => null);
249
276
  shell.start();
250
277
  void announceNewerRelease().catch(() => undefined);
251
278
  },
252
- flush: () => adapter.flushEvents(),
279
+ flush: () => backend.session.flushEvents(),
253
280
  waitUntilStopped: () => shell.waitUntilStopped(),
254
281
  dispose: async () => {
255
282
  try {
@@ -259,6 +286,8 @@ export async function composeOwnedUi(options = {}) {
259
286
  await releaseNoteAcknowledgement?.catch(() => undefined);
260
287
  }
261
288
  finally {
289
+ // Invariant: the shared spares outlive every shell and stop only after the last one is disposed.
290
+ clipboardServices?.dispose();
262
291
  unsubscribeAccent();
263
292
  sessionRuntimeDisposed = true;
264
293
  if (sessionRuntimeRefreshTimer !== null)
@@ -274,6 +303,8 @@ export async function composeOwnedUi(options = {}) {
274
303
  await releaseNoteClaim?.release();
275
304
  suggestionDiagnostics?.dispose();
276
305
  clipboardDiagnostics?.dispose();
306
+ // Invariant: the host outlives the application; disposing it cancels host-level probes last.
307
+ await host.dispose();
277
308
  }
278
309
  },
279
310
  };
@@ -1,4 +1,4 @@
1
1
  import type { ReferenceDocumentProvider } from "../features/owned-ui/reference-screen-app.js";
2
- import type { PiEngineAdapter } from "../integrations/pi/engine/adapter.js";
2
+ import type { OwnedUiSessionBackend } from "../contracts/owned-ui/index.js";
3
3
  /** Captures one current session snapshot and adapts it to the neutral reference document. */
4
- export declare function loadSessionInfoReference(adapter: PiEngineAdapter): Promise<ReferenceDocumentProvider>;
4
+ export declare function loadSessionInfoReference(backend: OwnedUiSessionBackend): Promise<ReferenceDocumentProvider>;
@@ -1,7 +1,7 @@
1
1
  import { renderPiShellSessionInfoReferenceDocument } from "../integrations/pi/components/shell-session-info-reference.js";
2
2
  /** Captures one current session snapshot and adapts it to the neutral reference document. */
3
- export async function loadSessionInfoReference(adapter) {
4
- const result = await adapter.executeWorkflow({ command: "session", argument: "" });
3
+ export async function loadSessionInfoReference(backend) {
4
+ const result = await backend.workflows.executeWorkflow({ command: "session", argument: "" });
5
5
  if (result.outcome !== "completed")
6
6
  throw new Error(result.message);
7
7
  if (result.presentation?.kind !== "session-info")
@@ -1,24 +1,4 @@
1
- import type { AgentJsonValue, AgentModelDescriptor, AgentSettingChangeOutcome, AgentResourceDescriptor, AgentSettingDescriptor } from "./domain.js";
2
- export interface AgentModelPort {
3
- readonly capabilities: {
4
- readonly selection: boolean;
5
- readonly refresh: boolean;
6
- readonly scopedCatalog: boolean;
7
- };
8
- listModels(scope?: string): Promise<readonly AgentModelDescriptor[]>;
9
- currentModel(): Promise<AgentModelDescriptor | null>;
10
- selectModel?(providerId: string, modelId: string): Promise<void>;
11
- refreshModels?(): Promise<void>;
12
- }
13
- export interface AgentAuthenticationPort {
14
- readonly capabilities: {
15
- readonly login: boolean;
16
- readonly logout: boolean;
17
- };
18
- status(providerId: string): Promise<"authenticated" | "unauthenticated" | "unavailable">;
19
- login?(providerId: string, signal?: AbortSignal): Promise<void>;
20
- logout?(providerId: string): Promise<void>;
21
- }
1
+ import type { AgentJsonValue, AgentSettingChangeOutcome, AgentSettingDescriptor } from "./domain.js";
22
2
  export interface AgentSettingsPort {
23
3
  readonly capabilities: {
24
4
  readonly write: boolean;
@@ -29,67 +9,3 @@ export interface AgentSettingsPort {
29
9
  writeSetting?(key: string, value: AgentJsonValue): Promise<AgentSettingChangeOutcome>;
30
10
  flush?(): Promise<void>;
31
11
  }
32
- export interface AgentResourcesPort {
33
- readonly capabilities: {
34
- readonly reload: boolean;
35
- readonly extensionBinding: boolean;
36
- };
37
- discoverResources(): Promise<readonly AgentResourceDescriptor[]>;
38
- reload?(): Promise<void>;
39
- bindExtensions?(sessionId: string): Promise<AgentExtensionBinding>;
40
- }
41
- export interface AgentExtensionBinding {
42
- readonly sessionId: string;
43
- dispose(): Promise<void>;
44
- }
45
- export interface AgentExtensionCommand {
46
- readonly name: string;
47
- readonly description: string;
48
- }
49
- export interface AgentSessionMetadata {
50
- readonly sessionId: string;
51
- readonly sessionName: string | null;
52
- readonly sessionPath: string | null;
53
- readonly cwd: string;
54
- }
55
- export interface AgentExtensionFailure {
56
- readonly extensionPath: string | null;
57
- readonly operation: string;
58
- readonly message: string;
59
- readonly recoverable: boolean;
60
- }
61
- export interface AgentExtensionPort {
62
- readonly capabilities: {
63
- readonly reload: boolean;
64
- readonly binding: boolean;
65
- readonly renderers: boolean;
66
- };
67
- discoverCommands(): Promise<readonly AgentExtensionCommand[]>;
68
- sessionMetadata(): Promise<AgentSessionMetadata>;
69
- bind?(sessionId: string): Promise<AgentExtensionBinding>;
70
- reload?(): Promise<void>;
71
- resolveMessageRenderer?(customType: string): unknown;
72
- resolveToolRenderer?(toolName: string): unknown;
73
- subscribeFailures(listener: (failure: AgentExtensionFailure) => void): () => void;
74
- }
75
- export interface AgentWorkflowDescriptor {
76
- readonly id: string;
77
- readonly label: string;
78
- readonly requiredCommands: readonly string[];
79
- }
80
- export interface AgentWorkflowPort {
81
- readonly capabilities: {
82
- readonly execute: boolean;
83
- };
84
- listWorkflows(): Promise<readonly AgentWorkflowDescriptor[]>;
85
- executeWorkflow?(workflowId: string, input: AgentJsonValue, signal?: AbortSignal): Promise<AgentJsonValue>;
86
- }
87
- export interface AgentServicePorts {
88
- readonly models: AgentModelPort;
89
- readonly authentication: AgentAuthenticationPort;
90
- readonly settings: AgentSettingsPort;
91
- readonly resources: AgentResourcesPort;
92
- readonly extensions: AgentExtensionPort;
93
- readonly workflows: AgentWorkflowPort;
94
- }
95
- export declare function assertAgentServicePorts(ports: AgentServicePorts): void;
@@ -1,35 +1 @@
1
- export function assertAgentServicePorts(ports) {
2
- required(ports.models, ["listModels", "currentModel"], "model");
3
- advertised(ports.models, "selection", "selectModel", "model");
4
- advertised(ports.models, "refresh", "refreshModels", "model");
5
- required(ports.authentication, ["status"], "authentication");
6
- advertised(ports.authentication, "login", "login", "authentication");
7
- advertised(ports.authentication, "logout", "logout", "authentication");
8
- required(ports.settings, ["listSettings", "readSetting"], "settings");
9
- advertised(ports.settings, "write", "writeSetting", "settings");
10
- advertised(ports.settings, "flush", "flush", "settings");
11
- required(ports.resources, ["discoverResources"], "resources");
12
- advertised(ports.resources, "reload", "reload", "resources");
13
- advertised(ports.resources, "extensionBinding", "bindExtensions", "resources");
14
- required(ports.extensions, ["discoverCommands", "sessionMetadata", "subscribeFailures"], "extensions");
15
- advertised(ports.extensions, "reload", "reload", "extensions");
16
- advertised(ports.extensions, "binding", "bind", "extensions");
17
- advertised(ports.extensions, "renderers", "resolveMessageRenderer", "extensions");
18
- advertised(ports.extensions, "renderers", "resolveToolRenderer", "extensions");
19
- required(ports.workflows, ["listWorkflows"], "workflow");
20
- advertised(ports.workflows, "execute", "executeWorkflow", "workflow");
21
- }
22
- function required(port, operations, label) {
23
- if (!port || typeof port.capabilities !== "object")
24
- throw new TypeError(`${label} port and capabilities are required`);
25
- for (const operation of operations)
26
- if (typeof port[operation] !== "function")
27
- throw new TypeError(`${label} port requires ${operation}`);
28
- }
29
- function advertised(port, capability, operation, label) {
30
- const enabled = port.capabilities[capability];
31
- if (typeof enabled !== "boolean")
32
- throw new TypeError(`${label} capability ${capability} must be explicit`);
33
- if (enabled && typeof port[operation] !== "function")
34
- throw new TypeError(`${label} capability ${capability} requires ${operation}`);
35
- }
1
+ export {};
@@ -1,11 +1,5 @@
1
- export { assertAgentServicePorts } from "./capability-ports.js";
2
- export type { AgentAuthenticationPort, AgentExtensionBinding, AgentExtensionCommand, AgentExtensionFailure, AgentExtensionPort, AgentModelPort, AgentResourcesPort, AgentServicePorts, AgentSessionMetadata, AgentSettingsPort, AgentWorkflowDescriptor, AgentWorkflowPort, } from "./capability-ports.js";
1
+ export type { AgentSettingsPort } from "./capability-ports.js";
3
2
  export type { AgentDomainCapabilities, AgentFailure, AgentFailureCategory, AgentJsonValue, AgentMessage, AgentMessageContent, AgentModelDescriptor, AgentResourceDescriptor, AgentSettingApplicationBoundary, AgentSettingChangeOutcome, AgentSettingDescriptor, AgentSettingFlag, AgentSettingOwner, AgentThemeDescriptor, AgentToolDescriptor, AgentUiContribution, AgentUsage, } from "./domain.js";
4
3
  export { assertAgentDomainCapabilities, assertAgentFailure, assertAgentMessage, assertAgentMessageContent, assertAgentModelDescriptor, assertAgentResourceDescriptor, assertAgentSettingDescriptor, assertAgentThemeDescriptor, assertAgentToolDescriptor, assertAgentUiContribution, assertAgentUsage, } from "./domain-validation.js";
5
- export { AGENT_ENGINE_CONTRACT_VERSION } from "./model.js";
6
- export type { AgentCapabilityContract, AgentCommand, AgentCommandCapability, AgentCommandId, AgentCommandOutcome, AgentEvent, AgentEventCapability, AgentEventSequence, AgentSessionId, AgentSessionLifecycle, AgentSnapshot, } from "./model.js";
7
4
  export { agentPackageOutcome, assertAgentPackagesPort } from "./package-ports.js";
8
5
  export type { AgentPackageDescriptor, AgentPackageDiagnostic, AgentPackageOperation, AgentPackageOutcome, AgentPackageProgress, AgentPackageStatus, AgentPackagesPort, AgentPackagesPortInput, } from "./package-ports.js";
9
- export type { AgentEnginePort, AgentSessionPort } from "./ports.js";
10
- export { assertAgentCapabilityContract, assertAgentCommand, assertAgentEvent, assertAgentSnapshot } from "./validation.js";
11
- export { decodeAgentCommand, decodeAgentEvent, decodeAgentSnapshot, encodeAgentCommand, encodeAgentEvent, encodeAgentSnapshot } from "./serialization.js";
@@ -1,6 +1,2 @@
1
- export { assertAgentServicePorts } from "./capability-ports.js";
2
1
  export { assertAgentDomainCapabilities, assertAgentFailure, assertAgentMessage, assertAgentMessageContent, assertAgentModelDescriptor, assertAgentResourceDescriptor, assertAgentSettingDescriptor, assertAgentThemeDescriptor, assertAgentToolDescriptor, assertAgentUiContribution, assertAgentUsage, } from "./domain-validation.js";
3
- export { AGENT_ENGINE_CONTRACT_VERSION } from "./model.js";
4
2
  export { agentPackageOutcome, assertAgentPackagesPort } from "./package-ports.js";
5
- export { assertAgentCapabilityContract, assertAgentCommand, assertAgentEvent, assertAgentSnapshot } from "./validation.js";
6
- export { decodeAgentCommand, decodeAgentEvent, decodeAgentSnapshot, encodeAgentCommand, encodeAgentEvent, encodeAgentSnapshot } from "./serialization.js";
@@ -3,7 +3,11 @@ export type UiAccentColor = "purple" | "blue" | "cyan" | "green" | "orange" | "p
3
3
  export { OWNED_UI_EXTENSION_CONTRACT_VERSION, OWNED_UI_EXTENSION_RENDER_CALLBACKS, OWNED_UI_EXTENSION_UI_CALLBACKS, OWNED_UI_EXTENSION_UI_PROPERTIES, assertOwnedUiExtensionUiPort, } from "./extension-ui.js";
4
4
  export type { OwnedUiExtensionAutocompleteItem, OwnedUiExtensionAutocompleteProvider, OwnedUiExtensionAutocompleteProviderFactory, OwnedUiExtensionAutocompleteSuggestions, OwnedUiExtensionComponent, OwnedUiExtensionComponentFactory, OwnedUiExtensionComponentFactoryContext, OwnedUiExtensionCustomFactory, OwnedUiExtensionCustomOptions, OwnedUiExtensionDialogOptions, OwnedUiExtensionEditorComponent, OwnedUiExtensionEditorFactory, OwnedUiExtensionEditorThemePort, OwnedUiExtensionEntryRenderInput, OwnedUiExtensionFooterDataPort, OwnedUiExtensionFooterFactory, OwnedUiExtensionInputListener, OwnedUiExtensionKeybindingsPort, OwnedUiExtensionMessageRenderInput, OwnedUiExtensionNotificationSeverity, OwnedUiExtensionOverlayAnchor, OwnedUiExtensionOverlayHandle, OwnedUiExtensionOverlayMargin, OwnedUiExtensionOverlayOptions, OwnedUiExtensionRenderCallback, OwnedUiExtensionRendererPort, OwnedUiExtensionRuntimePort, OwnedUiExtensionSelectListThemePort, OwnedUiExtensionSizeValue, OwnedUiExtensionTerminalPort, OwnedUiExtensionThemeBackground, OwnedUiExtensionThemeColor, OwnedUiExtensionThemeInfo, OwnedUiExtensionThemePort, OwnedUiExtensionToolRenderContext, OwnedUiExtensionUiCallback, OwnedUiExtensionUiPort, OwnedUiExtensionUiProperty, OwnedUiExtensionWidgetOptions, OwnedUiExtensionWidgetPlacement, OwnedUiExtensionWorkingIndicatorOptions, } from "./extension-ui.js";
5
5
  export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
6
- export type { OwnedUiBlockStatus, OwnedUiCommand, OwnedUiCommandOutcome, OwnedUiCorrelationId, OwnedUiCustomization, OwnedUiDiagnostics, OwnedUiDialog, OwnedUiEditorState, OwnedUiEntityId, OwnedUiEvent, OwnedUiFooterView, OwnedUiImageAttachment, OwnedUiLifecycle, OwnedUiModelInfo, OwnedUiOverlay, OwnedUiPromptSuggestionGeneratorPort, OwnedUiPromptSuggestionIdentity, OwnedUiPromptSuggestionReasoning, OwnedUiPromptSuggestionRequest, OwnedUiPromptSuggestionResult, OwnedUiPromptSuggestionState, OwnedUiQuitOutroSettings, OwnedUiQuitOutroSettingsPort, OwnedUiSessionId, OwnedUiSessionViewModel, OwnedUiSeverity, OwnedUiSlotId, OwnedUiSnapshot, OwnedUiStatusView, OwnedUiTerminalSurface, OwnedUiThinkingLevel, OwnedUiToolRendering, OwnedUiToolResultPart, OwnedUiToolState, OwnedUiTranscriptBlock, OwnedUiTranscriptBlockKind, OwnedUiTranscriptImageReference, OwnedUiUsageView, OwnedUiViewportSettings, OwnedUiViewportSettingsPort, } from "./model.js";
6
+ export type { OwnedUiBackgroundSettingsPort, OwnedUiBackgroundStyle, OwnedUiBlockStatus, OwnedUiCommand, OwnedUiCommandOutcome, OwnedUiCorrelationId, OwnedUiCustomization, OwnedUiDiagnostics, OwnedUiDialog, OwnedUiEditorState, OwnedUiEntityId, OwnedUiEvent, OwnedUiFooterView, OwnedUiImageAttachment, OwnedUiLifecycle, OwnedUiModelInfo, OwnedUiOverlay, OwnedUiPromptSuggestionGeneratorPort, OwnedUiPromptSuggestionIdentity, OwnedUiPromptSuggestionReasoning, OwnedUiPromptSuggestionRequest, OwnedUiPromptSuggestionResult, OwnedUiPromptSuggestionState, OwnedUiQuitOutroSettings, OwnedUiQuitOutroSettingsPort, OwnedUiSessionId, OwnedUiSessionViewModel, OwnedUiSeverity, OwnedUiSlotId, OwnedUiSnapshot, OwnedUiStatusView, OwnedUiTerminalSurface, OwnedUiThinkingLevel, OwnedUiToolRendering, OwnedUiToolResultPart, OwnedUiToolState, OwnedUiTranscriptBlock, OwnedUiTranscriptBlockKind, OwnedUiTranscriptImageReference, OwnedUiUsageView, OwnedUiViewportSettings, OwnedUiViewportSettingsPort, } from "./model.js";
7
+ export type { OwnedUiExtensionPort, OwnedUiSessionBackend, OwnedUiSessionCatalogPort, OwnedUiSessionFactory, OwnedUiSessionIdentityPort, OwnedUiSessionPort, OwnedUiSessionRequest, OwnedUiSessionSettingsPort, OwnedUiWorkflowPort, } from "./session-backend.js";
8
+ export type { OwnedUiDialogHost, OwnedUiInputSurface, OwnedUiSessionPresenters, OwnedUiShortcutDescription, OwnedUiTranscriptRendererPort, } from "./session-presenters.js";
9
+ export { OWNED_UI_HIDDEN_COMMAND_NAMES, OWNED_UI_MODELS_COMMAND_NAME, OWNED_UI_WORKFLOW_COMMAND_NAMES, } from "./session-workflows.js";
10
+ export type { OwnedUiAmbientAuthentication, OwnedUiAuthenticationProviderOption, OwnedUiAuthenticationProviderStatus, OwnedUiBashWorkflowResult, OwnedUiCacheWarmingPresentation, OwnedUiCommandResult, OwnedUiExtensionResourceSummary, OwnedUiExtensionSourceSummary, OwnedUiHiddenWorkflowCommandName, OwnedUiJsonValue, OwnedUiModelsCommandName, OwnedUiModelsContext, OwnedUiModelsRefreshResult, OwnedUiProjectTrustContext, OwnedUiProjectTrustUpdate, OwnedUiReleaseUpdate, OwnedUiResourceSummary, OwnedUiScopedModelDescriptor, OwnedUiScopedModelsContext, OwnedUiScopedModelsRefreshResult, OwnedUiSessionInfoPresentation, OwnedUiSessionProductMode, OwnedUiSessionResumeMetadata, OwnedUiSessionSettingKey, OwnedUiSessionSettingsSnapshot, OwnedUiSettingEffectHandler, OwnedUiSettingOwner, OwnedUiSettingOwnerHandlers, OwnedUiSettingsThinkingLevel, OwnedUiVisualExtensionSupport, OwnedUiWorkflowAutocompleteCommand, OwnedUiWorkflowCommandName, OwnedUiWorkflowInteractionHost, OwnedUiWorkflowInteractionRequest, OwnedUiWorkflowLoginNotification, OwnedUiWorkflowLoginStart, OwnedUiWorkflowMessage, OwnedUiWorkflowMessageKind, OwnedUiWorkflowOption, OwnedUiWorkflowOutcome, OwnedUiWorkflowPresentation, OwnedUiWorkflowRequest, OwnedUiWorkflowResult, OwnedUiWorkflowRoute, } from "./session-workflows.js";
7
11
  export { acceptsTranscriptUpdate, transcriptToolState } from "./transcript-lifecycle.js";
8
12
  export { DEFAULT_PROMPT_IMAGE_LIMIT, ImageAttachmentError, MAX_CLIPBOARD_TEXT_BYTES, MAX_IMAGE_DATA_BYTES, MAX_PROMPT_IMAGES, assertImageEncodedSize, assertPromptImages, } from "./image-attachments.js";
9
13
  export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
@@ -1,5 +1,6 @@
1
1
  export { OWNED_UI_EXTENSION_CONTRACT_VERSION, OWNED_UI_EXTENSION_RENDER_CALLBACKS, OWNED_UI_EXTENSION_UI_CALLBACKS, OWNED_UI_EXTENSION_UI_PROPERTIES, assertOwnedUiExtensionUiPort, } from "./extension-ui.js";
2
2
  export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
3
+ export { OWNED_UI_HIDDEN_COMMAND_NAMES, OWNED_UI_MODELS_COMMAND_NAME, OWNED_UI_WORKFLOW_COMMAND_NAMES, } from "./session-workflows.js";
3
4
  export { acceptsTranscriptUpdate, transcriptToolState } from "./transcript-lifecycle.js";
4
5
  export { DEFAULT_PROMPT_IMAGE_LIMIT, ImageAttachmentError, MAX_CLIPBOARD_TEXT_BYTES, MAX_IMAGE_DATA_BYTES, MAX_PROMPT_IMAGES, assertImageEncodedSize, assertPromptImages, } from "./image-attachments.js";
5
6
  export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
@@ -64,6 +64,12 @@ export interface OwnedUiViewportSettingsPort {
64
64
  snapshot(): OwnedUiViewportSettings;
65
65
  onChange(listener: (settings: OwnedUiViewportSettings) => void): () => void;
66
66
  }
67
+ export type OwnedUiBackgroundStyle = "transparent" | "accent" | "dark";
68
+ /** Narrow live canvas setting supplied only to the bare-A1 fullscreen presentation. */
69
+ export interface OwnedUiBackgroundSettingsPort {
70
+ snapshot(): OwnedUiBackgroundStyle;
71
+ onChange(listener: (style: OwnedUiBackgroundStyle) => void): () => void;
72
+ }
67
73
  /** Profile-local quit outro choice, read at the moment bare A1 quits. */
68
74
  export interface OwnedUiQuitOutroSettings {
69
75
  /** False leaves the terminal immediately; true plays the shell's fixed effect. */
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The session backend the owned shell presents. The shell and composition depend on this port,
3
+ * never on an engine adapter class, so a per-tab or non-Pi backend can stand behind the shell.
4
+ */
5
+ import type { OwnedUiExtensionUiPort } from "./extension-ui.js";
6
+ import type { OwnedUiCommand, OwnedUiEvent, OwnedUiImageAttachment, OwnedUiSessionViewModel, OwnedUiSnapshot } from "./model.js";
7
+ import type { OwnedUiAmbientAuthentication, OwnedUiAuthenticationProviderOption, OwnedUiBashWorkflowResult, OwnedUiCommandResult, OwnedUiExtensionResourceSummary, OwnedUiModelsContext, OwnedUiModelsRefreshResult, OwnedUiProjectTrustContext, OwnedUiProjectTrustUpdate, OwnedUiReleaseUpdate, OwnedUiResourceSummary, OwnedUiScopedModelsContext, OwnedUiScopedModelsRefreshResult, OwnedUiSessionProductMode, OwnedUiSessionResumeMetadata, OwnedUiSessionSettingsSnapshot, OwnedUiSettingOwner, OwnedUiSettingOwnerHandlers, OwnedUiSettingsThinkingLevel, OwnedUiVisualExtensionSupport, OwnedUiWorkflowAutocompleteCommand, OwnedUiWorkflowInteractionHost, OwnedUiWorkflowOption, OwnedUiWorkflowRequest, OwnedUiWorkflowResult } from "./session-workflows.js";
8
+ export interface OwnedUiSessionBackend {
9
+ readonly identity: OwnedUiSessionIdentityPort;
10
+ readonly session: OwnedUiSessionPort;
11
+ readonly workflows: OwnedUiWorkflowPort;
12
+ readonly settings: OwnedUiSessionSettingsPort;
13
+ readonly catalog: OwnedUiSessionCatalogPort;
14
+ readonly extensions: OwnedUiExtensionPort;
15
+ }
16
+ /** What a caller states about the session it wants; everything process-wide stays with the factory. */
17
+ export interface OwnedUiSessionRequest {
18
+ /** Unique within the process. Omitted means the factory assigns one that is. */
19
+ readonly sessionId?: string;
20
+ readonly cwd: string;
21
+ }
22
+ /**
23
+ * The one place sessions come from. The factory owns the state that is process-wide, so two
24
+ * sessions in one process never install, announce, or trace the same thing twice.
25
+ */
26
+ export interface OwnedUiSessionFactory {
27
+ create(request: OwnedUiSessionRequest): Promise<OwnedUiSessionBackend>;
28
+ }
29
+ /** Which session this is, where it lives, and how often it has been replaced. */
30
+ export interface OwnedUiSessionIdentityPort {
31
+ readonly sessionId: string;
32
+ readonly agentDir: string;
33
+ readonly cwd: string;
34
+ /** Advances on every session replacement and on delivery-only callback invalidation. */
35
+ readonly sessionGeneration: number;
36
+ /** Actual session replacements, excluding delivery-only invalidation of callbacks. */
37
+ readonly sessionBindingGeneration: number;
38
+ readonly disposed: boolean;
39
+ currentSessionResumeMetadata(): OwnedUiSessionResumeMetadata | null;
40
+ }
41
+ /** The session lifecycle, its view, its event stream, and command admission. */
42
+ export interface OwnedUiSessionPort {
43
+ start(): Promise<OwnedUiSessionViewModel>;
44
+ view(): OwnedUiSessionViewModel;
45
+ snapshot(): OwnedUiSnapshot;
46
+ /** Subscribe to events; the listener first receives the current view. Returns the unsubscribe. */
47
+ onEvent(listener: (event: OwnedUiEvent) => void): () => void;
48
+ execute(command: OwnedUiCommand): Promise<OwnedUiCommandResult>;
49
+ /** Settle queued delivery; rejects when required delivery was interrupted. */
50
+ flushEvents(): Promise<void>;
51
+ dispose(): Promise<void>;
52
+ }
53
+ /** Slash-command workflows and the shell-side host their interactive steps call back into. */
54
+ export interface OwnedUiWorkflowPort {
55
+ executeWorkflow(request: OwnedUiWorkflowRequest): Promise<OwnedUiWorkflowResult>;
56
+ executeBashWorkflow(command: string, excludeFromContext: boolean): Promise<OwnedUiBashWorkflowResult>;
57
+ cycleModelWorkflow(direction: "forward" | "backward"): Promise<OwnedUiWorkflowResult>;
58
+ workflowAutocompleteCommands(): readonly OwnedUiWorkflowAutocompleteCommand[];
59
+ /** Clear queued steering and follow-up submissions, returning their texts in order. */
60
+ clearQueuedWorkflows(): readonly string[];
61
+ /** The result a blocked `/reload` reported, or null when reload is available. */
62
+ reloadBlockedResult(): OwnedUiWorkflowResult | null;
63
+ /** Copy through the active clipboard owner; true means acknowledged delivery. */
64
+ copyWorkflowText(text: string): Promise<boolean>;
65
+ setWorkflowInteractionHost(interaction: OwnedUiWorkflowInteractionHost): void;
66
+ }
67
+ /**
68
+ * Engine settings the shell reads and the live effects it installs. Settings writes stay here
69
+ * rather than in `OwnedUiCommand`: commands are admitted per session, and a global default must
70
+ * not be gated by one session's admission or overload state.
71
+ */
72
+ export interface OwnedUiSessionSettingsPort {
73
+ readonly productMode: OwnedUiSessionProductMode;
74
+ snapshot(): OwnedUiSessionSettingsSnapshot;
75
+ /** Bind live effects for one owner; returns the unbind. */
76
+ bindOwner(owner: OwnedUiSettingOwner, handlers: OwnedUiSettingOwnerHandlers): () => void;
77
+ /** Persist the global thinking default without changing the live session level. */
78
+ setDefaultThinkingLevel(level: OwnedUiSettingsThinkingLevel): void;
79
+ /**
80
+ * The theme the engine is configured with, in the engine's own grammar: a theme's name, or a
81
+ * `light/dark` pair meaning "follow the terminal".
82
+ */
83
+ configuredTheme(): string | undefined;
84
+ }
85
+ /** Models, scopes, project trust, and authentication choices. */
86
+ export interface OwnedUiSessionCatalogPort {
87
+ modelsContext(): OwnedUiModelsContext;
88
+ setSessionModelScope(scopeIds: readonly string[]): void;
89
+ persistModelScope(scopeIds: readonly string[]): void;
90
+ refreshModels(signal: AbortSignal): Promise<OwnedUiModelsRefreshResult>;
91
+ pinnedScopedModelsContext(): OwnedUiScopedModelsContext;
92
+ updateScopedModels(enabledModelIds: readonly string[] | null): void;
93
+ persistScopedModels(enabledModelIds: readonly string[] | null): void;
94
+ refreshScopedModels(signal: AbortSignal): Promise<OwnedUiScopedModelsRefreshResult>;
95
+ pinnedProjectTrustContext(): OwnedUiProjectTrustContext;
96
+ persistProjectTrust(updates: readonly OwnedUiProjectTrustUpdate[]): void;
97
+ pinnedLoginOptions(authType?: "oauth" | "api_key"): readonly OwnedUiAuthenticationProviderOption[];
98
+ pinnedLoginMethodOptions(providerReference: string): {
99
+ readonly title: string;
100
+ readonly options: readonly OwnedUiWorkflowOption[];
101
+ };
102
+ pinnedAmbientAuthentication(selection: string): OwnedUiAmbientAuthentication | null;
103
+ pinnedLogoutOptions(): Promise<readonly OwnedUiAuthenticationProviderOption[]>;
104
+ pinnedForkOptions(): readonly OwnedUiWorkflowOption[];
105
+ }
106
+ /** Loaded resources, the extension UI bridge, transcript images, and clipboard binding. */
107
+ export interface OwnedUiExtensionPort {
108
+ nonVisualResources(): readonly OwnedUiResourceSummary[];
109
+ extensionResources(): readonly OwnedUiExtensionResourceSummary[];
110
+ resolveTranscriptImage(assetId: string): OwnedUiImageAttachment | null;
111
+ visualExtensionSupport(): OwnedUiVisualExtensionSupport;
112
+ /** Attach the shell's extension UI and bind it to the current session. */
113
+ bindExtensionUi(ui: OwnedUiExtensionUiPort, shutdown?: () => void | Promise<void>): Promise<void>;
114
+ unbindExtensionUi(): Promise<void>;
115
+ /** Bind the owned UI's clipboard lifecycle; true from the writer means acknowledged delivery. Returns the unbind. */
116
+ bindClipboardWriter(writer: (text: string) => Promise<boolean>): () => void;
117
+ /** Report a newer release found by the startup check. */
118
+ announceReleaseUpdate(release: OwnedUiReleaseUpdate): void;
119
+ }