@timurproko/a1 0.2.7-dev.806 → 0.2.7-dev.809

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 (105) hide show
  1. package/dist/app/session-shell/dialog-coordinator.d.ts +42 -0
  2. package/dist/app/session-shell/dialog-coordinator.js +133 -0
  3. package/dist/app/session-shell/dock-chrome.d.ts +34 -0
  4. package/dist/app/session-shell/dock-chrome.js +109 -0
  5. package/dist/app/session-shell/exit-notice.d.ts +1 -1
  6. package/dist/app/session-shell/exit-notice.js +1 -1
  7. package/dist/app/session-shell/extension-surface.d.ts +30 -0
  8. package/dist/app/session-shell/extension-surface.js +105 -0
  9. package/dist/app/session-shell/input-surface-switch.d.ts +36 -0
  10. package/dist/app/session-shell/input-surface-switch.js +85 -0
  11. package/dist/app/session-shell/login-interaction.d.ts +27 -0
  12. package/dist/app/session-shell/login-interaction.js +91 -0
  13. package/dist/app/session-shell/prompt-submission.d.ts +48 -0
  14. package/dist/app/session-shell/prompt-submission.js +276 -0
  15. package/dist/app/session-shell/resident-tab-coordinator.d.ts +41 -0
  16. package/dist/app/session-shell/resident-tab-coordinator.js +120 -0
  17. package/dist/app/session-shell/session-concern.d.ts +22 -0
  18. package/dist/app/session-shell/session-concern.js +29 -0
  19. package/dist/app/session-shell/session-lifecycle.d.ts +29 -0
  20. package/dist/app/session-shell/session-lifecycle.js +49 -0
  21. package/dist/app/session-shell/session-shell-root.d.ts +1 -1
  22. package/dist/app/session-shell/session-shell-root.js +182 -931
  23. package/dist/app/session-shell/session-shell.d.ts +2 -8
  24. package/dist/app/session-shell/session-shell.js +209 -897
  25. package/dist/app/session-shell/settings-bindings.d.ts +17 -0
  26. package/dist/app/session-shell/settings-bindings.js +91 -0
  27. package/dist/app/session-shell/shell-editor-factory.d.ts +27 -0
  28. package/dist/app/session-shell/shell-editor-factory.js +102 -0
  29. package/dist/app/session-shell/shell-host.d.ts +6 -0
  30. package/dist/app/session-shell/shell-host.js +26 -4
  31. package/dist/app/session-shell/shell-layout.d.ts +64 -0
  32. package/dist/app/session-shell/shell-layout.js +18 -0
  33. package/dist/app/session-shell/suggestion-surface.d.ts +25 -0
  34. package/dist/app/session-shell/suggestion-surface.js +63 -0
  35. package/dist/app/session-shell/transcript-document.d.ts +78 -0
  36. package/dist/app/session-shell/transcript-document.js +365 -0
  37. package/dist/app/session-shell/viewport-layout.d.ts +31 -0
  38. package/dist/app/session-shell/viewport-layout.js +160 -0
  39. package/dist/app/session-shell/workflow-output.d.ts +33 -0
  40. package/dist/app/session-shell/workflow-output.js +174 -0
  41. package/dist/app/session-shell/workflow-router.d.ts +25 -0
  42. package/dist/app/session-shell/workflow-router.js +39 -0
  43. package/dist/composition/owned-ui.d.ts +6 -25
  44. package/dist/composition/owned-ui.js +48 -242
  45. package/dist/composition/resident-tab-bridge.d.ts +16 -0
  46. package/dist/composition/resident-tab-bridge.js +159 -0
  47. package/dist/composition/session-backend.d.ts +19 -0
  48. package/dist/composition/session-backend.js +1 -0
  49. package/dist/composition/session-runtime-registry.d.ts +20 -0
  50. package/dist/composition/session-runtime-registry.js +85 -0
  51. package/dist/composition/settings-route-host.d.ts +6 -1
  52. package/dist/composition/settings-route-host.js +7 -6
  53. package/dist/composition/startup-route.d.ts +32 -0
  54. package/dist/composition/startup-route.js +72 -0
  55. package/dist/features/owned-ui/settings-app.d.ts +4 -1
  56. package/dist/features/owned-ui/settings-app.js +9 -3
  57. package/dist/features/resident-tab/shortcut-declarations.js +1 -1
  58. package/dist/features/resident-tab/status-deriver.d.ts +4 -3
  59. package/dist/features/resident-tab/status-deriver.js +2 -5
  60. package/dist/foundation/release/bootstrap.js +2 -2
  61. package/dist/foundation/resident-tabs/bridge-client.d.ts +1 -1
  62. package/dist/foundation/resident-tabs/bridge-client.js +2 -1
  63. package/dist/foundation/resident-tabs/fixture-control.d.ts +7 -0
  64. package/dist/foundation/resident-tabs/fixture-control.js +35 -0
  65. package/dist/foundation/resident-tabs/progress-observation.d.ts +7 -0
  66. package/dist/foundation/resident-tabs/progress-observation.js +119 -0
  67. package/dist/foundation/terminal-cleanup/index.d.ts +1 -1
  68. package/dist/foundation/terminal-cleanup/index.js +1 -1
  69. package/dist/foundation/terminal-cleanup/terminal-reset.d.ts +5 -0
  70. package/dist/foundation/terminal-cleanup/terminal-reset.js +5 -0
  71. package/dist/integrations/pi/engine/adapter.d.ts +4 -77
  72. package/dist/integrations/pi/engine/adapter.js +85 -393
  73. package/dist/integrations/pi/engine/command-dispatch.d.ts +13 -0
  74. package/dist/integrations/pi/engine/command-dispatch.js +57 -0
  75. package/dist/integrations/pi/engine/host.js +2 -2
  76. package/dist/integrations/pi/engine/ports.d.ts +56 -0
  77. package/dist/integrations/pi/engine/ports.js +89 -0
  78. package/dist/integrations/pi/engine/session-runtime.js +5 -2
  79. package/dist/integrations/pi/engine/view-state.d.ts +42 -0
  80. package/dist/integrations/pi/engine/view-state.js +126 -0
  81. package/dist/integrations/pi/tui-runtime/adapter.d.ts +6 -0
  82. package/dist/integrations/pi/tui-runtime/adapter.js +28 -1
  83. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +11 -0
  84. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +30 -1
  85. package/dist/native/darwin-arm64/manifest.json +1 -1
  86. package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
  87. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  88. package/dist/native/darwin-x64/manifest.json +1 -1
  89. package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
  90. package/dist/native/darwin-x64/terminal-host.node +0 -0
  91. package/dist/native/linux-x64/manifest.json +1 -1
  92. package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
  93. package/dist/native/linux-x64/terminal-host.node +0 -0
  94. package/dist/native/win32-x64/manifest.json +2 -2
  95. package/dist/native/win32-x64/process-guardian.node +0 -0
  96. package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
  97. package/dist/native/win32-x64/terminal-host.node +0 -0
  98. package/dist/product-identity.d.ts +2 -2
  99. package/dist/product-identity.js +2 -2
  100. package/dist/product-identity.json +6 -0
  101. package/dist/ui/settings/manager.d.ts +6 -0
  102. package/dist/ui/settings/manager.js +25 -0
  103. package/docs/architecture/boundaries.md +14 -0
  104. package/docs/architecture/resident-tabs.md +23 -18
  105. package/package.json +2 -1
@@ -0,0 +1,174 @@
1
+ import { createPiShellArmin, createPiShellEarendilAnnouncement, } from "../../integrations/pi/components/shell-selectors-dialogs.js";
2
+ import { createPiShellChangelog, createPiShellHotkeys, createPiShellSessionInfo, renderPiShellCommandMessage, renderPiShellStatusText, } from "../../integrations/pi/components/shell-presenters-info.js";
3
+ import { piShellHyperlink } from "../../integrations/pi/components/shell-shared-facade.js";
4
+ /**
5
+ * Presents workflow results: bare A1 answers in the dock notice, the pinned profile appends
6
+ * transcript-anchored output, and consecutive status lines at the same anchor replace each other.
7
+ */
8
+ export class WorkflowOutput {
9
+ #ports;
10
+ #sequence = 0;
11
+ #statusMessages = new Map();
12
+ #lastStatusId;
13
+ constructor(ports) {
14
+ this.#ports = ports;
15
+ }
16
+ appendStatus(message) {
17
+ // Rationale: bare A1 acknowledges commands in one dock notice above the editor, where the
18
+ // reader's eye already is, instead of a transcript row that opens an empty session at the
19
+ // top-left or sinks into a long feed. The pinned route keeps Pi's chat placement.
20
+ if (this.#ports.customViewport) {
21
+ this.#ports.dock.setNotice({ kind: "status", message });
22
+ return;
23
+ }
24
+ const { document } = this.#ports;
25
+ const previousId = this.#lastStatusId;
26
+ if (previousId !== undefined
27
+ && document.lastId === previousId
28
+ && document.anchorOf(previousId) === this.#ports.transcriptLength()) {
29
+ this.#statusMessages.set(previousId, message);
30
+ document.invalidate("workflow-status");
31
+ this.#ports.invalidate();
32
+ return;
33
+ }
34
+ const id = this.#appendAnchored(width => [
35
+ "",
36
+ ...renderPiShellStatusText(this.#statusMessages.get(id) ?? message, width),
37
+ ]);
38
+ this.#statusMessages.set(id, message);
39
+ this.#lastStatusId = id;
40
+ }
41
+ appendMessage(message, errorCode) {
42
+ if (message.kind === "status") {
43
+ this.appendStatus(message.message);
44
+ return;
45
+ }
46
+ if (this.#ports.customViewport && (message.kind === "warning" || message.kind === "error")) {
47
+ this.#ports.dock.setNotice({
48
+ kind: errorCode === "image-count" ? "warning" : message.kind,
49
+ message: message.message,
50
+ ...(errorCode === undefined ? {} : { errorCode }),
51
+ });
52
+ return;
53
+ }
54
+ this.#lastStatusId = undefined;
55
+ const presentation = { kind: message.kind, message: message.message };
56
+ this.#appendAnchored(width => renderPiShellCommandMessage(presentation, width, this.#ports.outputPad()));
57
+ }
58
+ appendResult(result, errorCode) {
59
+ if (result.messages !== undefined) {
60
+ for (const message of result.messages)
61
+ this.appendMessage(message, errorCode);
62
+ return;
63
+ }
64
+ if (result.messageKind === "silent" || (result.outcome === "cancelled" && result.messageKind === undefined))
65
+ return;
66
+ if (result.command === "reload" && result.outcome === "completed") {
67
+ this.appendStatus(result.message);
68
+ return;
69
+ }
70
+ if (result.outcome === "completed" && this.#appendPresentation(result))
71
+ return;
72
+ if (result.outcome === "failed") {
73
+ this.appendMessage({
74
+ kind: result.messageKind === "warning" ? "warning" : "error",
75
+ message: result.message,
76
+ }, errorCode);
77
+ return;
78
+ }
79
+ if (result.outcome === "completed" && (result.command === "quit" || result.command === "compact"))
80
+ return;
81
+ if (result.outcome === "completed" && result.command === "new" && this.#ports.customViewport) {
82
+ // Rationale: bare A1 keeps the replacement session visually empty while preserving Pi's accent notice shape.
83
+ this.#ports.dock.setNotice({ kind: "new-session", message: result.message });
84
+ return;
85
+ }
86
+ if (result.outcome === "completed" && (result.command === "new" || result.command === "name" || result.command === "debug")) {
87
+ this.#lastStatusId = undefined;
88
+ const presentation = { kind: result.command, message: result.message, ...(result.detail === undefined ? {} : { detail: result.detail }) };
89
+ this.#appendAnchored(width => renderPiShellCommandMessage(presentation, width, this.#ports.outputPad()));
90
+ return;
91
+ }
92
+ if (result.outcome === "completed" && this.#appendAnnouncement(result.command))
93
+ return;
94
+ // Rationale: the pinned engine links both share URLs; the workflow result carries the plain URLs.
95
+ const message = result.command !== "share" ? result.message
96
+ : result.detail ? `${linkShareUrl(result.message)}\nGist: ${piShellHyperlink(result.detail)}`
97
+ // Protocol: Radius shares carry only the artifact URL.
98
+ : linkShareUrl(result.message);
99
+ this.appendStatus(message);
100
+ }
101
+ /** Drops every anchored output and the status-replacement chain. */
102
+ reset() {
103
+ this.#ports.document.removeAnchored();
104
+ this.#statusMessages.clear();
105
+ this.#lastStatusId = undefined;
106
+ }
107
+ // Invariant: session info, hotkeys, and changelog draw their own components; false for any other completed command.
108
+ #appendPresentation(result) {
109
+ if (result.command === "session" && result.presentation?.kind === "session-info") {
110
+ this.#lastStatusId = undefined;
111
+ const sessionInfo = createPiShellSessionInfo(result.presentation);
112
+ this.#appendAnchored(width => sessionInfo.render(width), () => sessionInfo.dispose?.());
113
+ return true;
114
+ }
115
+ if (result.command === "hotkeys") {
116
+ this.#lastStatusId = undefined;
117
+ const presentation = this.#ports.hotkeysPresentation();
118
+ const hotkeys = createPiShellHotkeys(presentation.bindings, presentation.getShortcuts, presentation.profile, presentation.residentTabs);
119
+ this.#appendAnchored(width => hotkeys.render(width), () => hotkeys.dispose?.());
120
+ return true;
121
+ }
122
+ if (result.command === "changelog") {
123
+ this.#lastStatusId = undefined;
124
+ const changelog = createPiShellChangelog(result.detail ?? "No changelog entries found.");
125
+ this.#appendAnchored(width => changelog.render(width), () => changelog.dispose?.());
126
+ return true;
127
+ }
128
+ return false;
129
+ }
130
+ // Invariant: the two easter-egg announcements; false for any other command.
131
+ #appendAnnouncement(command) {
132
+ if (command === "arminsayshi") {
133
+ this.#lastStatusId = undefined;
134
+ const armin = createPiShellArmin(this.#ports.componentRuntime);
135
+ this.#appendAnchored(width => ["", ...armin.render(width)], () => armin.dispose?.());
136
+ return true;
137
+ }
138
+ if (command === "dementedelves") {
139
+ this.#lastStatusId = undefined;
140
+ const announcement = createPiShellEarendilAnnouncement();
141
+ this.#appendAnchored(width => ["", ...announcement.render(width)], () => announcement.dispose?.());
142
+ return true;
143
+ }
144
+ return false;
145
+ }
146
+ #appendAnchored(render, dispose) {
147
+ // Invariant: transcript-bound workflow output supersedes a pending acknowledgement.
148
+ this.#ports.dock.dismissNotice();
149
+ this.#sequence += 1;
150
+ const id = `workflow-status-${this.#sequence}`;
151
+ const component = {
152
+ id,
153
+ revision: 1,
154
+ render,
155
+ handleInput() { },
156
+ invalidate() { },
157
+ update() { },
158
+ setExpanded() { },
159
+ setOutputPad() { },
160
+ setHideThinkingBlock() { },
161
+ setMermaidRenderingMode() { },
162
+ setImagePresentation() { },
163
+ ...(dispose === undefined ? {} : { dispose }),
164
+ };
165
+ this.#ports.document.appendAnchored(id, component, this.#ports.transcriptLength());
166
+ this.#ports.invalidate();
167
+ return id;
168
+ }
169
+ }
170
+ /** "Share URL: <url>" with the URL made clickable; other share wordings pass through unchanged. */
171
+ function linkShareUrl(message) {
172
+ const match = /^Share URL: (\S+)$/.exec(message);
173
+ return match === null ? message : `Share URL: ${piShellHyperlink(match[1])}`;
174
+ }
@@ -0,0 +1,25 @@
1
+ import type { OwnedUiCommandResult, OwnedUiWorkflowRequest } from "../../contracts/owned-ui/index.js";
2
+ /** The owned selectors a workflow can open in place of asking the engine to choose. */
3
+ export interface WorkflowSelectors {
4
+ showScopedModelsSelector(): void;
5
+ showModelsDialog(initialQuery?: string): void;
6
+ showModelSelector(initialSearchInput?: string): void;
7
+ showForkSelector(): void;
8
+ showThinkingSelector(): Promise<void>;
9
+ showTrustSelector(): void;
10
+ showSettingsSelector(): void;
11
+ showSessionSelector(): Promise<void>;
12
+ showLoginAuthTypeSelector(): void;
13
+ showLoginMethodSelector(providerReference: string): void;
14
+ showLogoutSelector(): Promise<void>;
15
+ showTreeSelector(): Promise<void>;
16
+ }
17
+ /**
18
+ * Opens the owned selector a workflow request asks for when the user has not chosen yet. Returns
19
+ * the command result when a selector handled the request, settling once an asynchronous selector
20
+ * has opened, or undefined when the request goes to the engine. The decision itself is synchronous,
21
+ * so a request that goes to the engine reaches it in the same turn.
22
+ */
23
+ export declare function openWorkflowSelector(request: OwnedUiWorkflowRequest, selectors: WorkflowSelectors, options: {
24
+ readonly residentTab: boolean;
25
+ }): OwnedUiCommandResult | Promise<OwnedUiCommandResult> | undefined;
@@ -0,0 +1,39 @@
1
+ const unchosen = (request) => request.selection === undefined && request.confirmed === undefined;
2
+ const unchosenBare = (request) => unchosen(request) && request.argument.trim().length === 0;
3
+ // Invariant: the routes are checked in this order, matching the order the workflows were introduced.
4
+ const SELECTOR_ROUTES = [
5
+ { command: "scoped-models", pending: unchosen, open: selectors => selectors.showScopedModelsSelector() },
6
+ { command: "models", pending: request => request.selection === undefined, open: (selectors, request) => selectors.showModelsDialog(request.argument.trim() || undefined) },
7
+ { command: "model", pending: unchosenBare, open: selectors => selectors.showModelSelector() },
8
+ { command: "fork", pending: unchosen, open: selectors => selectors.showForkSelector() },
9
+ { command: "thinking", pending: request => request.selection === undefined && request.argument.trim().length === 0, open: selectors => selectors.showThinkingSelector() },
10
+ { command: "trust", pending: unchosen, open: selectors => selectors.showTrustSelector() },
11
+ { command: "settings", pending: unchosen, open: selectors => selectors.showSettingsSelector() },
12
+ { command: "resume", pending: unchosenBare, open: selectors => selectors.showSessionSelector() },
13
+ {
14
+ command: "login",
15
+ pending: unchosen,
16
+ open: (selectors, request) => request.argument.trim().length === 0
17
+ ? selectors.showLoginAuthTypeSelector()
18
+ : selectors.showLoginMethodSelector(request.argument),
19
+ },
20
+ { command: "logout", pending: unchosen, open: selectors => selectors.showLogoutSelector() },
21
+ { command: "tree", pending: unchosenBare, open: selectors => selectors.showTreeSelector() },
22
+ ];
23
+ /**
24
+ * Opens the owned selector a workflow request asks for when the user has not chosen yet. Returns
25
+ * the command result when a selector handled the request, settling once an asynchronous selector
26
+ * has opened, or undefined when the request goes to the engine. The decision itself is synchronous,
27
+ * so a request that goes to the engine reaches it in the same turn.
28
+ */
29
+ export function openWorkflowSelector(request, selectors, options) {
30
+ const route = SELECTOR_ROUTES.find(candidate => candidate.command === request.command && candidate.pending(request));
31
+ if (route === undefined)
32
+ return undefined;
33
+ if (route.command === "settings" && options.residentTab) {
34
+ return { outcome: "rejected", diagnostic: "Settings is available from the global Settings tab." };
35
+ }
36
+ const completed = { outcome: "completed", diagnostic: null };
37
+ const opened = route.open(selectors, request);
38
+ return opened instanceof Promise ? opened.then(() => completed) : completed;
39
+ }
@@ -1,32 +1,16 @@
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 PiEngineHostOptions, type PiEngineSessionRequest } from "../integrations/pi/engine/host.js";
5
- import { type PiSessionPresenterBackend } from "../integrations/pi/session-presenters/index.js";
4
+ import { type PiEngineHostOptions } from "../integrations/pi/engine/host.js";
6
5
  import type { PiProjectTrustPreflightPrompt } from "../integrations/pi/engine/project-trust-preflight.js";
7
6
  import type { PiSessionForkPrompt } from "../integrations/pi/engine/session-selection.js";
8
7
  import { OwnedSettingsManager } from "../ui/settings/manager.js";
9
8
  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";
12
9
  import type { ReleaseNoteCatalog } from "../features/owned-ui/release-notes.js";
13
10
  import type { TabBridgeClient } from "../foundation/resident-tabs/bridge-client.js";
14
- import { ResidentTabRecovery } from "../foundation/resident-tabs/recovery.js";
15
- /**
16
- * The session backend composition wires: the owned-UI port, the prompt-suggestion generator, and
17
- * the agent settings port. `settingsPort` stays outside the owned-UI contract because its type
18
- * belongs to the agent-engine contracts, which the owned-UI contract may not import.
19
- */
20
- export interface ComposedSessionBackend extends PiSessionPresenterBackend, OwnedUiPromptSuggestionGeneratorPort {
21
- settingsPort(): AgentSettingsPort | null;
22
- generateResidentTabName(instruction: string, maxTokens: number, signal: AbortSignal): Promise<string | null>;
23
- }
24
- /** The process-level engine host as composition drives it: sessions, the live accent, and disposal. */
25
- export interface ComposedEngineHost {
26
- create(request: PiEngineSessionRequest): Promise<ComposedSessionBackend>;
27
- setAccentColor(color: UiAccentColor): void;
28
- dispose(): Promise<void>;
29
- }
11
+ import type { ComposedEngineHost } from "./session-backend.js";
12
+ export type { ComposedEngineHost, ComposedSessionBackend } from "./session-backend.js";
13
+ export { bindResidentTabBridge, correlateResidentTabSubmission } from "./resident-tab-bridge.js";
30
14
  export interface OwnedUiCompositionOptions {
31
15
  readonly cwd?: string;
32
16
  readonly terminal?: PresentationTerminalPort;
@@ -85,8 +69,5 @@ export declare function residentStartupPresentation(resident: boolean, fallbackN
85
69
  };
86
70
  export declare function composeOwnedUiApplication(options?: OwnedUiCompositionOptions): Promise<OwnedUiApplicationPort>;
87
71
  export declare function composeOwnedUi(options?: OwnedUiCompositionOptions): Promise<OwnedUiComposition>;
88
- export declare function bindResidentTabBridge(tabBridge: TabBridgeClient, backend: Pick<ComposedSessionBackend, "identity" | "session" | "workflows" | "generateResidentTabName">, recovery?: Pick<ResidentTabRecovery, "settled"> | null, options?: {
89
- readonly autoName?: boolean;
90
- readonly openRoute?: (route: "settings") => void;
91
- }): Promise<() => void>;
92
- export declare function correlateResidentTabSubmission(recovery: Pick<ResidentTabRecovery, "correlated" | "settled">, backend: Pick<ComposedSessionBackend, "identity" | "session">, submissionId: string, entryId: string): Promise<void>;
72
+ /** Rereads the shared settings document whenever its stat changes; returns the stop. */
73
+ export declare function watchSharedSettings(settings: Pick<OwnedSettingsManager, "file" | "refresh">): () => void;