@timurproko/a1 0.2.6-dev.717 → 0.2.6-dev.727
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.
- package/bin/cli.js +13 -2
- package/bin/ui.js +13 -0
- package/dist/app/session-shell/prompt-suggestion-controller.d.ts +5 -4
- package/dist/app/session-shell/prompt-suggestion-controller.js +148 -58
- package/dist/app/session-shell/session-shell-root.d.ts +2 -1
- package/dist/app/session-shell/session-shell-root.js +13 -6
- package/dist/app/session-shell/session-shell.js +45 -3
- package/dist/app/session-shell/session-viewport-controller.js +33 -21
- package/dist/cli/dispatch.js +5 -3
- package/dist/cli/session-context.d.ts +5 -1
- package/dist/cli/session-context.js +25 -8
- package/dist/composition/owned-ui.d.ts +3 -0
- package/dist/composition/owned-ui.js +66 -6
- package/dist/composition/settings-route-host.js +2 -1
- package/dist/contracts/owned-ui/index.d.ts +4 -2
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/model.d.ts +4 -0
- package/dist/contracts/owned-ui/suggestion-diagnostics.d.ts +5 -1
- package/dist/contracts/owned-ui/suggestion-diagnostics.js +3 -1
- package/dist/contracts/owned-ui/validation.js +7 -0
- package/dist/features/launch/index.d.ts +1 -1
- package/dist/features/launch/session-context.d.ts +17 -2
- package/dist/features/launch/session-context.js +9 -5
- package/dist/features/owned-ui/settings-app.js +21 -39
- package/dist/features/prompt-suggestions/diagnostics.js +4 -1
- package/dist/foundation/lifecycle/index.d.ts +2 -2
- package/dist/foundation/lifecycle/index.js +1 -1
- package/dist/foundation/lifecycle/session-repository-context.d.ts +19 -2
- package/dist/foundation/lifecycle/session-repository-context.js +434 -66
- package/dist/foundation/process-containment/index.d.ts +1 -0
- package/dist/foundation/process-containment/index.js +1 -0
- package/dist/foundation/process-containment/native-process-inspector.d.ts +3 -0
- package/dist/foundation/process-containment/native-process-inspector.js +21 -0
- package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
- package/dist/foundation/release/progress-palette.generated.js +2 -2
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/components.js +2 -2
- package/dist/integrations/pi/components/index.d.ts +2 -2
- package/dist/integrations/pi/components/index.js +1 -1
- package/dist/integrations/pi/components/modal-frame.js +3 -4
- package/dist/integrations/pi/components/models-dialog.js +5 -5
- package/dist/integrations/pi/components/prompt-input-port.d.ts +1 -0
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/share-operation-dialog.js +3 -3
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +8 -7
- package/dist/integrations/pi/components/shell-extension-ui.d.ts +2 -0
- package/dist/integrations/pi/components/shell-extension-ui.js +20 -10
- package/dist/integrations/pi/components/shell-hotkey-sections.js +2 -2
- package/dist/integrations/pi/components/shell-presenters-info.js +10 -10
- package/dist/integrations/pi/components/shell-presenters-transcript.js +10 -10
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -6
- package/dist/integrations/pi/components/shell-shared-facade.js +1 -1
- package/dist/integrations/pi/components/skills-dialog.js +3 -3
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +2 -3
- package/dist/integrations/pi/components/theme.d.ts +9 -0
- package/dist/integrations/pi/components/theme.js +30 -0
- package/dist/integrations/pi/components/tool-result-adapter.js +6 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +6 -6
- package/dist/integrations/pi/components/upstream/components/extension-input.js +4 -4
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +4 -4
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +5 -5
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +8 -5
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +3 -3
- package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +9 -9
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +6 -3
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +2 -2
- package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +4 -0
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +11 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +27 -18
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +4 -4
- package/dist/integrations/pi/components/upstream/history/editor-core.js +11 -7
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +31 -0
- package/dist/integrations/pi/components/upstream/program-status-reporter.js +89 -0
- package/dist/integrations/pi/components/upstream/theme/system-theme.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/system-theme.js +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.d.ts +18 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +207 -10
- package/dist/integrations/pi/engine/pi-settings-metadata.json +1 -1
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/session-events.js +10 -2
- package/dist/integrations/pi/engine/transcript-projection.js +2 -1
- package/dist/integrations/pi/startup-public.js +306 -290
- package/dist/integrations/pi/startup-public.manifest.json +289 -265
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -1
- package/dist/integrations/pi/tui-runtime/adapter.js +7 -0
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +3 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/product-identity.d.ts +2 -2
- package/dist/product-identity.js +2 -2
- package/dist/product-identity.json +3 -1
- package/dist/runtime-payload-inventory.json +3092 -2878
- package/dist/ui/components/prompt-input.d.ts +2 -0
- package/dist/ui/components/prompt-input.js +5 -1
- package/dist/ui/components/text-selection.d.ts +1 -1
- package/dist/ui/components/text-selection.js +3 -1
- package/dist/ui/components/theme.d.ts +2 -0
- package/dist/ui/components/transcript-viewport.d.ts +6 -4
- package/dist/ui/components/transcript-viewport.js +94 -16
- package/dist/ui/components/value-menu.d.ts +2 -0
- package/dist/ui/components/value-menu.js +13 -8
- package/dist/ui/settings/declarations.d.ts +26 -14
- package/dist/ui/settings/declarations.js +24 -11
- package/dist/ui/settings/migrations.js +16 -0
- package/docs/architecture/project-structure.md +4 -3
- package/docs/architecture/prompt-suggestions.md +14 -10
- package/docs/local-worktree-cleanup.md +11 -5
- package/docs/openspec-archive-automation.md +6 -5
- package/package.json +3 -3
|
@@ -306,14 +306,14 @@ export class SessionViewportController {
|
|
|
306
306
|
if (this.#viewport.clearSelection())
|
|
307
307
|
this.#requestRender();
|
|
308
308
|
}
|
|
309
|
-
else {
|
|
309
|
+
else if (this.#viewport.hasSelection) {
|
|
310
310
|
const copySelection = this.#viewport.captureSelectedText();
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
311
|
+
this.#viewport.clearSelection();
|
|
312
|
+
this.#stopSelectionAutoScroll();
|
|
313
|
+
this.#requestRender();
|
|
314
|
+
return copySelection === null
|
|
315
|
+
? { data: "", consumed: true }
|
|
316
|
+
: { data: "", consumed: true, copySelection };
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
const previousPrompt = SHIFT_UP_INPUTS.has(data) || this.#editor.matchesTerminalKey(data, "alt+home");
|
|
@@ -412,12 +412,19 @@ export class SessionViewportController {
|
|
|
412
412
|
}
|
|
413
413
|
if (this.#dockPointerSuppressed || this.#tailPointerSuppressed)
|
|
414
414
|
return true;
|
|
415
|
+
const pendingEditorClick = this.#pendingEditorClick;
|
|
416
|
+
if (pendingEditorClick !== undefined) {
|
|
417
|
+
if (event.column === pendingEditorClick.column && event.row === pendingEditorClick.row)
|
|
418
|
+
return true;
|
|
419
|
+
this.#pendingEditorClick = undefined;
|
|
420
|
+
this.#viewport.pressSelection(pendingEditorClick.column, pendingEditorClick.row, now, { continueMultiClick: false });
|
|
421
|
+
this.#viewport.extendSelection(event.column, event.row, now, false);
|
|
422
|
+
this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
|
|
423
|
+
activity = true;
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
415
426
|
if (this.#viewport.selectionActive) {
|
|
416
427
|
this.#viewport.extendSelection(event.column, event.row, now, false);
|
|
417
|
-
if (this.#pendingEditorClick !== undefined
|
|
418
|
-
&& (event.column !== this.#pendingEditorClick.column || event.row !== this.#pendingEditorClick.row)) {
|
|
419
|
-
this.#pendingEditorClick = undefined;
|
|
420
|
-
}
|
|
421
428
|
this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight, frame.rows.length);
|
|
422
429
|
activity = true;
|
|
423
430
|
return true;
|
|
@@ -500,11 +507,13 @@ export class SessionViewportController {
|
|
|
500
507
|
}
|
|
501
508
|
if (event.row >= 1 && event.row <= frame.rows.length && event.column <= frame.descriptor.width) {
|
|
502
509
|
if (editorFrame !== undefined && event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
|
|
510
|
+
// Invariant: no-drag prompt clicks remain visually editor-owned. Distinct
|
|
511
|
+
// motion promotes from this exact origin into complete-frame selection.
|
|
503
512
|
this.#pendingEditorClick = { column: event.column, row: event.row };
|
|
504
513
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
514
|
+
else {
|
|
515
|
+
this.#viewport.pressSelection(event.column, event.row, now);
|
|
516
|
+
}
|
|
508
517
|
repaint = true;
|
|
509
518
|
return true;
|
|
510
519
|
}
|
|
@@ -525,19 +534,22 @@ export class SessionViewportController {
|
|
|
525
534
|
repaint = true;
|
|
526
535
|
return true;
|
|
527
536
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const pendingEditorClick = this.#pendingEditorClick;
|
|
537
|
+
const pendingEditorClick = this.#pendingEditorClick;
|
|
538
|
+
if (pendingEditorClick !== undefined) {
|
|
531
539
|
this.#pendingEditorClick = undefined;
|
|
532
|
-
if (
|
|
533
|
-
this.#viewport.clearSelection();
|
|
540
|
+
if (this.#editorPointerFrame !== undefined) {
|
|
534
541
|
const editorRow = pendingEditorClick.row - this.#editorPointerFrame.rowStart + 1;
|
|
535
542
|
this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
536
543
|
this.#editor.handlePointer({ kind: "release", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
537
544
|
}
|
|
538
|
-
|
|
545
|
+
forceRepaint = true;
|
|
546
|
+
repaint = true;
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
if (this.#viewport.releaseSelection()) {
|
|
550
|
+
this.#stopSelectionAutoScroll();
|
|
551
|
+
if (this.#copyOnSelect)
|
|
539
552
|
completedCopy = this.#viewport.captureSelectedText() ?? undefined;
|
|
540
|
-
}
|
|
541
553
|
// Platform: restore OSC 8 links only after the held-button selection paint has
|
|
542
554
|
// ended, then overwrite any terminal-cached hover cells immediately.
|
|
543
555
|
forceRepaint = true;
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -18,6 +18,7 @@ export function cliUsage(capabilities) {
|
|
|
18
18
|
"remove <source>",
|
|
19
19
|
"uninstall <source>",
|
|
20
20
|
"list",
|
|
21
|
+
"session worktrees",
|
|
21
22
|
"session link-worktree <path>",
|
|
22
23
|
"session unlink-worktree",
|
|
23
24
|
]);
|
|
@@ -47,6 +48,7 @@ export function cliHelp(capabilities) {
|
|
|
47
48
|
` ${command} list`,
|
|
48
49
|
"",
|
|
49
50
|
"Session context:",
|
|
51
|
+
` ${command} session worktrees`,
|
|
50
52
|
` ${command} session link-worktree <path>`,
|
|
51
53
|
` ${command} session unlink-worktree`,
|
|
52
54
|
"",
|
|
@@ -127,12 +129,12 @@ function parseSessionContext(rest) {
|
|
|
127
129
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic("session link-worktree accepts one path.") };
|
|
128
130
|
return { kind: "session-context", request: { action, path: value } };
|
|
129
131
|
}
|
|
130
|
-
if (action === "unlink-worktree") {
|
|
132
|
+
if (action === "unlink-worktree" || action === "worktrees") {
|
|
131
133
|
if (value !== undefined)
|
|
132
|
-
return { kind: "error", message: PRODUCT_TEXT.diagnostic(
|
|
134
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`session ${action} does not accept arguments.`) };
|
|
133
135
|
return { kind: "session-context", request: { action } };
|
|
134
136
|
}
|
|
135
|
-
return { kind: "error", message: PRODUCT_TEXT.diagnostic("session accepts link-worktree <path
|
|
137
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic("session accepts worktrees, link-worktree <path>, or unlink-worktree.") };
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
140
|
* Stable update is the empty form. `--develop` selects the moving development
|
|
@@ -2,8 +2,12 @@ import { type SessionContextRequest } from "../features/launch/index.js";
|
|
|
2
2
|
export type { SessionContextRequest } from "../features/launch/index.js";
|
|
3
3
|
export interface SessionContextCommandOptions {
|
|
4
4
|
readonly environment?: NodeJS.ProcessEnv;
|
|
5
|
+
readonly inspectProcess?: (pid: number) => Promise<{
|
|
6
|
+
readonly pid: number;
|
|
7
|
+
readonly startIdentity: string;
|
|
8
|
+
} | null>;
|
|
5
9
|
readonly stdout?: (message: string) => void;
|
|
6
10
|
readonly stderr?: (message: string) => void;
|
|
7
11
|
}
|
|
8
|
-
/** Apply repository
|
|
12
|
+
/** Apply repository context only when invoked by an exact live A1 shell-tool runtime. */
|
|
9
13
|
export declare function runSessionContextCommand(request: SessionContextRequest, options?: SessionContextCommandOptions): Promise<number>;
|
|
@@ -1,29 +1,46 @@
|
|
|
1
1
|
import { updateSessionRepositoryContext, } from "../features/launch/index.js";
|
|
2
|
-
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
3
|
-
/** Apply repository
|
|
2
|
+
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../product-identity.js";
|
|
3
|
+
/** Apply repository context only when invoked by an exact live A1 shell-tool runtime. */
|
|
4
4
|
export async function runSessionContextCommand(request, options = {}) {
|
|
5
5
|
const environment = options.environment ?? process.env;
|
|
6
6
|
const stdout = options.stdout ?? (message => process.stdout.write(message));
|
|
7
7
|
const stderr = options.stderr ?? (message => process.stderr.write(message));
|
|
8
8
|
const identity = readIdentity(environment);
|
|
9
9
|
if (identity === null) {
|
|
10
|
-
stderr(`${PRODUCT_TEXT.diagnostic("session context requires an active A1 shell-tool session.")}\n`);
|
|
10
|
+
stderr(`${PRODUCT_TEXT.diagnostic("session context requires an active A1 shell-tool session runtime.")}\n`);
|
|
11
11
|
return 2;
|
|
12
12
|
}
|
|
13
13
|
try {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (options.inspectProcess === undefined)
|
|
15
|
+
throw Object.assign(new Error("native process identity inspection is unavailable"), { code: "process-inspection-unavailable" });
|
|
16
|
+
const outcome = await updateSessionRepositoryContext({ sessionId: identity.sessionId, sessionFile: identity.sessionFile }, request, { runtimeId: identity.runtimeId, inspectProcess: options.inspectProcess });
|
|
17
|
+
if (outcome.kind === "unlinked")
|
|
18
|
+
stdout("Session worktree context cleared.\n");
|
|
19
|
+
if (outcome.kind === "linked")
|
|
20
|
+
stdout(`Session worktree context linked: ${outcome.cwd}\n`);
|
|
21
|
+
if (outcome.kind === "worktrees") {
|
|
22
|
+
for (const entry of outcome.entries)
|
|
23
|
+
stdout(`${entry.status}: ${entry.cwd} (${entry.branch})\n`);
|
|
24
|
+
}
|
|
16
25
|
return 0;
|
|
17
26
|
}
|
|
18
27
|
catch (error) {
|
|
19
|
-
|
|
28
|
+
const code = errorCode(error);
|
|
29
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
30
|
+
stderr(`${PRODUCT_TEXT.diagnostic(`could not update session context${code === null ? "" : ` (${code})`}: ${detail}`)}\n`);
|
|
20
31
|
return 1;
|
|
21
32
|
}
|
|
22
33
|
}
|
|
23
34
|
function readIdentity(environment) {
|
|
24
35
|
const sessionId = environment.PI_SESSION_ID;
|
|
25
36
|
const sessionFile = environment.PI_SESSION_FILE;
|
|
26
|
-
|
|
37
|
+
const runtimeId = environment[PRODUCT_IDENTITY.environment.sessionRuntimeId];
|
|
38
|
+
if (!sessionId || !sessionFile || !runtimeId)
|
|
27
39
|
return null;
|
|
28
|
-
return { sessionId, sessionFile };
|
|
40
|
+
return { sessionId, sessionFile, runtimeId };
|
|
41
|
+
}
|
|
42
|
+
function errorCode(error) {
|
|
43
|
+
if (error instanceof Error && "code" in error && typeof error.code === "string")
|
|
44
|
+
return error.code;
|
|
45
|
+
return null;
|
|
29
46
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AvailableRelease, StartupReleaseCheckOptions } from "../foundation/release/latest-release.js";
|
|
2
|
+
import type { NativeProcessIdentity } from "../foundation/lifecycle/model.js";
|
|
2
3
|
import type { SessionSelection } from "../foundation/lifecycle/session-selection.js";
|
|
3
4
|
import type { PiEngineAdapter } from "../integrations/pi/engine/adapter.js";
|
|
4
5
|
import type { PiProjectTrustPreflightPrompt } from "../integrations/pi/engine/project-trust-preflight.js";
|
|
@@ -34,6 +35,8 @@ export interface OwnedUiCompositionOptions {
|
|
|
34
35
|
readonly releaseNotes?: ReleaseNoteCatalog;
|
|
35
36
|
/** Startup release-availability seam; defaults to the throttled registry check. */
|
|
36
37
|
readonly checkForNewerRelease?: (options: StartupReleaseCheckOptions) => Promise<AvailableRelease | null>;
|
|
38
|
+
/** Exact native process inspection injected by the shipped entry; absent SDK seams do not publish claims. */
|
|
39
|
+
readonly inspectProcess?: (pid: number) => Promise<NativeProcessIdentity | null>;
|
|
37
40
|
}
|
|
38
41
|
export interface OwnedUiComposition {
|
|
39
42
|
readonly application: OwnedUiApplicationPort;
|
|
@@ -6,8 +6,7 @@ import { PromptImageSidecar } from "../features/prompt-history/image-sidecar.js"
|
|
|
6
6
|
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
|
-
import {
|
|
10
|
-
import { applyConfiguredPiTheme, getAvailablePiThemes } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
9
|
+
import { applyConfiguredPiTheme, getAvailablePiThemes, setPiAccentColor, setPiPackageBorderProjectionEnabled } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
11
10
|
import { createPiEngineAdapter } from "../integrations/pi/engine/adapter.js";
|
|
12
11
|
import { ClipboardDiagnosticCapture } from "../app/session-shell/clipboard-diagnostics.js";
|
|
13
12
|
import { OwnedUiSessionShell } from "../app/session-shell/session-shell.js";
|
|
@@ -16,12 +15,46 @@ import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/presentat
|
|
|
16
15
|
import { createOwnedRouteHost } from "./settings-route-host.js";
|
|
17
16
|
import { renderPiShellChangelogLines } from "../integrations/pi/components/shell-presenters-info.js";
|
|
18
17
|
import { nativeHyperlinkStyle } from "../ui/components/spans.js";
|
|
18
|
+
const SESSION_RUNTIME_REFRESH_MS = 30_000;
|
|
19
19
|
export async function composeOwnedUiApplication(options = {}) {
|
|
20
20
|
return (await composeOwnedUi(options)).application;
|
|
21
21
|
}
|
|
22
22
|
export async function composeOwnedUi(options = {}) {
|
|
23
23
|
const cwd = options.cwd ?? process.cwd();
|
|
24
24
|
const ownedSurfaces = options.ownedSurfaces !== "off";
|
|
25
|
+
const sessionRuntimeId = ownedSurfaces ? process.env[PRODUCT_IDENTITY.environment.sessionRuntimeId] : undefined;
|
|
26
|
+
const inspectSessionProcess = options.inspectProcess;
|
|
27
|
+
let sessionRuntimeIdentity = null;
|
|
28
|
+
let activeSessionIdentity = null;
|
|
29
|
+
let sessionRuntimeRefreshTimer = null;
|
|
30
|
+
let sessionRuntimeRefresh = Promise.resolve();
|
|
31
|
+
let sessionRuntimeDisposed = false;
|
|
32
|
+
const runtimeIdentity = async () => {
|
|
33
|
+
if (sessionRuntimeId === undefined || inspectSessionProcess === undefined)
|
|
34
|
+
return null;
|
|
35
|
+
sessionRuntimeIdentity ??= inspectSessionProcess(process.pid).catch(() => null);
|
|
36
|
+
return await sessionRuntimeIdentity;
|
|
37
|
+
};
|
|
38
|
+
const queueSessionRuntimeRefresh = () => {
|
|
39
|
+
if (sessionRuntimeDisposed || activeSessionIdentity === null || sessionRuntimeId === undefined || inspectSessionProcess === undefined)
|
|
40
|
+
return;
|
|
41
|
+
sessionRuntimeRefresh = sessionRuntimeRefresh.then(async () => {
|
|
42
|
+
const identity = activeSessionIdentity;
|
|
43
|
+
if (sessionRuntimeDisposed || identity === null)
|
|
44
|
+
return;
|
|
45
|
+
const owner = await runtimeIdentity();
|
|
46
|
+
if (owner === null)
|
|
47
|
+
return;
|
|
48
|
+
const { registerSessionRepositoryRuntime } = await import("../foundation/lifecycle/session-repository-context.js");
|
|
49
|
+
await registerSessionRepositoryRuntime(identity, sessionRuntimeId, owner, { inspectProcess: inspectSessionProcess });
|
|
50
|
+
}).catch(() => undefined);
|
|
51
|
+
};
|
|
52
|
+
const armSessionRuntimeRefresh = () => {
|
|
53
|
+
if (sessionRuntimeRefreshTimer !== null)
|
|
54
|
+
return;
|
|
55
|
+
sessionRuntimeRefreshTimer = setInterval(queueSessionRuntimeRefresh, SESSION_RUNTIME_REFRESH_MS);
|
|
56
|
+
sessionRuntimeRefreshTimer.unref();
|
|
57
|
+
};
|
|
25
58
|
const adapter = options.createPiAdapter
|
|
26
59
|
? await options.createPiAdapter()
|
|
27
60
|
: await createPiEngineAdapter({
|
|
@@ -30,7 +63,16 @@ export async function composeOwnedUi(options = {}) {
|
|
|
30
63
|
settingsProductMode: ownedSurfaces ? "bare" : "comparison",
|
|
31
64
|
announceStartupChangelog: !ownedSurfaces,
|
|
32
65
|
...(ownedSurfaces ? {
|
|
33
|
-
repositoryContextReader: async (sessionId, sessionFile, signal) =>
|
|
66
|
+
repositoryContextReader: async (sessionId, sessionFile, signal) => {
|
|
67
|
+
const owner = await runtimeIdentity();
|
|
68
|
+
if (owner === null || sessionRuntimeId === undefined || inspectSessionProcess === undefined)
|
|
69
|
+
return null;
|
|
70
|
+
activeSessionIdentity = { sessionId, sessionFile };
|
|
71
|
+
const { activateSessionRepositoryContext } = await import("../foundation/lifecycle/session-repository-context.js");
|
|
72
|
+
const context = await activateSessionRepositoryContext(activeSessionIdentity, sessionRuntimeId, owner, { signal, inspectProcess: inspectSessionProcess });
|
|
73
|
+
armSessionRuntimeRefresh();
|
|
74
|
+
return context;
|
|
75
|
+
},
|
|
34
76
|
} : {}),
|
|
35
77
|
...(options.sessionPath === undefined ? {} : { sessionPath: options.sessionPath }),
|
|
36
78
|
...(options.sessionSelection === undefined ? {} : { sessionSelection: options.sessionSelection }),
|
|
@@ -67,10 +109,15 @@ export async function composeOwnedUi(options = {}) {
|
|
|
67
109
|
: await import("../features/owned-ui/release-note-state.js").then(module => module.claimReleaseNote({
|
|
68
110
|
configDir: productPaths.configDir, profileId: options.profileId, version: currentReleaseNote.version,
|
|
69
111
|
}));
|
|
70
|
-
// Compatibility: bare A1 intentionally ships one visual target while its UI is being completed:
|
|
71
|
-
// dark, regardless of terminal detection or a previously stored Pi theme.
|
|
72
|
-
// comparison
|
|
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");
|
|
73
117
|
applyConfiguredPiTheme(ownedSurfaces ? "dark" : adapter.configuredTheme());
|
|
118
|
+
const unsubscribeAccent = settings === null || !ownedSurfaces
|
|
119
|
+
? () => { }
|
|
120
|
+
: settings.onChange(current => setPiAccentColor(current.value("accentColor")));
|
|
74
121
|
// Rationale: Routes open only after shell construction.
|
|
75
122
|
const references = {
|
|
76
123
|
changelog: async (input) => {
|
|
@@ -167,6 +214,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
167
214
|
});
|
|
168
215
|
}
|
|
169
216
|
catch (error) {
|
|
217
|
+
unsubscribeAccent();
|
|
170
218
|
await releaseNoteClaim?.release();
|
|
171
219
|
clipboardDiagnostics?.dispose();
|
|
172
220
|
suggestionDiagnostics?.dispose();
|
|
@@ -211,6 +259,18 @@ export async function composeOwnedUi(options = {}) {
|
|
|
211
259
|
await releaseNoteAcknowledgement?.catch(() => undefined);
|
|
212
260
|
}
|
|
213
261
|
finally {
|
|
262
|
+
unsubscribeAccent();
|
|
263
|
+
sessionRuntimeDisposed = true;
|
|
264
|
+
if (sessionRuntimeRefreshTimer !== null)
|
|
265
|
+
clearInterval(sessionRuntimeRefreshTimer);
|
|
266
|
+
sessionRuntimeRefreshTimer = null;
|
|
267
|
+
await sessionRuntimeRefresh;
|
|
268
|
+
const owner = await runtimeIdentity();
|
|
269
|
+
if (sessionRuntimeId !== undefined && owner !== null) {
|
|
270
|
+
await import("../foundation/lifecycle/session-repository-context.js")
|
|
271
|
+
.then(module => module.releaseSessionRepositoryRuntime(sessionRuntimeId, owner))
|
|
272
|
+
.catch(() => undefined);
|
|
273
|
+
}
|
|
214
274
|
await releaseNoteClaim?.release();
|
|
215
275
|
suggestionDiagnostics?.dispose();
|
|
216
276
|
clipboardDiagnostics?.dispose();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CHANGELOG_ROUTE, HOTKEYS_ROUTE, HOTKEYS_TITLE } from "../features/owned-ui/reference-routes.js";
|
|
2
2
|
import { SETTINGS_APP_ID, SETTINGS_ROUTE } from "../features/owned-ui/settings-route.js";
|
|
3
|
-
import { piTheme } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
3
|
+
import { piTheme, renderPiAccentPreview } from "../integrations/pi/components/upstream/theme/theme.js";
|
|
4
4
|
import { faint } from "../ui/components/text.js";
|
|
5
5
|
/** Declares settings and lazy document routes. */
|
|
6
6
|
export function createOwnedRouteHost(settings, references) {
|
|
@@ -130,6 +130,7 @@ function pinnedTheme() {
|
|
|
130
130
|
fg: (token, text) => piTheme().fg(token, text),
|
|
131
131
|
bold: (text) => piTheme().bold(text),
|
|
132
132
|
plain: (text) => text,
|
|
133
|
+
accentPreview: (color, text) => renderPiAccentPreview(color, text),
|
|
133
134
|
disabled: (text) => faint(piTheme().fg("dim", text)),
|
|
134
135
|
highlight: (text) => piTheme().bg("selectedBg", text),
|
|
135
136
|
panel: (text) => `\u001b[48;2;55;55;55m${text}\u001b[49m`,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Stable stored choices for bare A1's semantic UI accent. */
|
|
2
|
+
export type UiAccentColor = "purple" | "blue" | "cyan" | "green" | "orange" | "pink";
|
|
1
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";
|
|
2
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";
|
|
3
5
|
export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
|
|
@@ -7,8 +9,8 @@ export { DEFAULT_PROMPT_IMAGE_LIMIT, ImageAttachmentError, MAX_CLIPBOARD_TEXT_BY
|
|
|
7
9
|
export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
|
|
8
10
|
export { canonicalPromptChipMatches, protectPromptChipWrapping, replaceCanonicalPromptChips } from "./prompt-chips.js";
|
|
9
11
|
export type { PromptChipTextMatch, PromptChipWrapProtection } from "./prompt-chips.js";
|
|
10
|
-
export { SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
11
|
-
export type { SuggestionDecision, SuggestionDecisionReason, SuggestionDiagnosticEvent, SuggestionDiagnosticObserver, SuggestionDiagnosticRecord, } from "./suggestion-diagnostics.js";
|
|
12
|
+
export { SUGGESTION_ATTEMPT_TRIGGERS, SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
13
|
+
export type { SuggestionAttemptTrigger, SuggestionDecision, SuggestionDecisionReason, SuggestionDiagnosticEvent, SuggestionDiagnosticObserver, SuggestionDiagnosticRecord, } from "./suggestion-diagnostics.js";
|
|
12
14
|
export { PROMPT_HISTORY_EDITOR_REPLACEMENT, PROMPT_HISTORY_MAX_ENTRY_BYTES, PROMPT_HISTORY_MAX_PENDING, PROMPT_HISTORY_MAX_TEXT_BYTES, assertPromptHistorySubmission, } from "./prompt-history.js";
|
|
13
15
|
export type { PromptHistoryFailure, PromptHistoryImageSidecarAttachment, PromptHistoryImageSidecarPort, PromptHistoryImageSidecarRecord, PromptHistoryKind, PromptHistoryPort, PromptHistoryResult, PromptHistorySnapshot, PromptHistorySubmission, } from "./prompt-history.js";
|
|
14
16
|
export { assertOwnedUiCommand, assertOwnedUiCustomization, assertOwnedUiDiagnostics, assertOwnedUiEditorState, assertOwnedUiEvent, assertOwnedUiPromptSuggestionIdentity, assertOwnedUiPromptSuggestionRequest, assertOwnedUiPromptSuggestionResult, assertOwnedUiPromptSuggestionState, assertOwnedUiSessionViewModel, assertOwnedUiSnapshot, assertOwnedUiStatusView, assertOwnedUiTerminalSurface, assertOwnedUiTranscriptBlock, } from "./validation.js";
|
|
@@ -4,6 +4,6 @@ export { acceptsTranscriptUpdate, transcriptToolState } from "./transcript-lifec
|
|
|
4
4
|
export { DEFAULT_PROMPT_IMAGE_LIMIT, ImageAttachmentError, MAX_CLIPBOARD_TEXT_BYTES, MAX_IMAGE_DATA_BYTES, MAX_PROMPT_IMAGES, assertImageEncodedSize, assertPromptImages, } from "./image-attachments.js";
|
|
5
5
|
export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
|
|
6
6
|
export { canonicalPromptChipMatches, protectPromptChipWrapping, replaceCanonicalPromptChips } from "./prompt-chips.js";
|
|
7
|
-
export { SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
7
|
+
export { SUGGESTION_ATTEMPT_TRIGGERS, SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
8
8
|
export { PROMPT_HISTORY_EDITOR_REPLACEMENT, PROMPT_HISTORY_MAX_ENTRY_BYTES, PROMPT_HISTORY_MAX_PENDING, PROMPT_HISTORY_MAX_TEXT_BYTES, assertPromptHistorySubmission, } from "./prompt-history.js";
|
|
9
9
|
export { assertOwnedUiCommand, assertOwnedUiCustomization, assertOwnedUiDiagnostics, assertOwnedUiEditorState, assertOwnedUiEvent, assertOwnedUiPromptSuggestionIdentity, assertOwnedUiPromptSuggestionRequest, assertOwnedUiPromptSuggestionResult, assertOwnedUiPromptSuggestionState, assertOwnedUiSessionViewModel, assertOwnedUiSnapshot, assertOwnedUiStatusView, assertOwnedUiTerminalSurface, assertOwnedUiTranscriptBlock, } from "./validation.js";
|
|
@@ -336,6 +336,10 @@ export type OwnedUiEvent = {
|
|
|
336
336
|
readonly model: OwnedUiModelInfo | null;
|
|
337
337
|
readonly assistantMessageCount: number;
|
|
338
338
|
readonly successful: boolean;
|
|
339
|
+
readonly stopReason: string | null;
|
|
340
|
+
readonly toolContinuation: boolean;
|
|
341
|
+
/** Pi 1.1 distinguishes user cancellation from an ordinary or failed settlement. */
|
|
342
|
+
readonly aborted: boolean;
|
|
339
343
|
} | {
|
|
340
344
|
readonly type: "editor-state";
|
|
341
345
|
readonly sessionId: OwnedUiSessionId;
|
|
@@ -2,12 +2,16 @@ import type { OwnedUiPromptSuggestionReasoning } from "./model.js";
|
|
|
2
2
|
export declare const SUGGESTION_DECISION_REASONS: readonly ["disabled", "disposed", "early-conversation", "no-model", "failed-response", "incomplete-response", "tool-continuation", "replacement-input", "modal", "draft", "not-ready", "not-focused", "autocomplete", "prompt-mode", "presentation-unavailable", "ineligible", "stale-identity"];
|
|
3
3
|
export type SuggestionDecisionReason = typeof SUGGESTION_DECISION_REASONS[number];
|
|
4
4
|
export type SuggestionDecision = SuggestionDecisionReason | null;
|
|
5
|
-
export declare const SUGGESTION_DIAGNOSTIC_EVENTS: readonly ["skipped", "started", "displayed", "empty", "rejected", "provider-failure", "unavailable", "timeout", "cancelled", "stale-result", "presentation-blocked", "late-result-discarded"];
|
|
5
|
+
export declare const SUGGESTION_DIAGNOSTIC_EVENTS: readonly ["skipped", "started", "displayed", "empty", "rejected", "provider-failure", "unavailable", "timeout", "cancelled", "stale-result", "presentation-blocked", "presentation-deferred", "retry-exhausted", "late-result-discarded"];
|
|
6
6
|
export type SuggestionDiagnosticEvent = typeof SUGGESTION_DIAGNOSTIC_EVENTS[number];
|
|
7
|
+
export declare const SUGGESTION_ATTEMPT_TRIGGERS: readonly ["prefetch", "settlement", "retry"];
|
|
8
|
+
export type SuggestionAttemptTrigger = typeof SUGGESTION_ATTEMPT_TRIGGERS[number];
|
|
7
9
|
/** Metadata only: never carry a session path, prompt, candidate, or raw error. */
|
|
8
10
|
export interface SuggestionDiagnosticRecord {
|
|
9
11
|
readonly event: SuggestionDiagnosticEvent;
|
|
10
12
|
readonly reason?: SuggestionDecisionReason;
|
|
13
|
+
readonly attempt?: number;
|
|
14
|
+
readonly trigger?: SuggestionAttemptTrigger;
|
|
11
15
|
readonly session: number;
|
|
12
16
|
readonly run: number;
|
|
13
17
|
readonly response: number;
|
|
@@ -5,5 +5,7 @@ export const SUGGESTION_DECISION_REASONS = [
|
|
|
5
5
|
];
|
|
6
6
|
export const SUGGESTION_DIAGNOSTIC_EVENTS = [
|
|
7
7
|
"skipped", "started", "displayed", "empty", "rejected", "provider-failure", "unavailable",
|
|
8
|
-
"timeout", "cancelled", "stale-result", "presentation-blocked", "
|
|
8
|
+
"timeout", "cancelled", "stale-result", "presentation-blocked", "presentation-deferred",
|
|
9
|
+
"retry-exhausted", "late-result-discarded",
|
|
9
10
|
];
|
|
11
|
+
export const SUGGESTION_ATTEMPT_TRIGGERS = ["prefetch", "settlement", "retry"];
|
|
@@ -133,6 +133,13 @@ export function assertOwnedUiEvent(event) {
|
|
|
133
133
|
assertOwnedUiModelInfo(event.model);
|
|
134
134
|
if (typeof event.successful !== "boolean")
|
|
135
135
|
throw new TypeError("owned-UI settlement success state is invalid");
|
|
136
|
+
if (event.stopReason === undefined)
|
|
137
|
+
throw new TypeError("owned-UI settlement stop reason is missing");
|
|
138
|
+
assertOptionalText(event.stopReason, "owned-UI settlement stop reason", MAX_LABEL_LENGTH);
|
|
139
|
+
if (typeof event.toolContinuation !== "boolean")
|
|
140
|
+
throw new TypeError("owned-UI settlement tool-continuation state is invalid");
|
|
141
|
+
if (typeof event.aborted !== "boolean")
|
|
142
|
+
throw new TypeError("owned-UI settlement aborted state is invalid");
|
|
136
143
|
return;
|
|
137
144
|
case "editor-state":
|
|
138
145
|
assertOwnedUiEditorState(event.editor);
|
|
@@ -9,6 +9,6 @@ export type { LaunchProfilePathOptions, LaunchProfilePaths } from "./profile-pat
|
|
|
9
9
|
export { prepareInteractiveLaunch } from "./prepare-launch.js";
|
|
10
10
|
export type { PrepareInteractiveLaunchOptions, PreparedInteractiveLaunch } from "./prepare-launch.js";
|
|
11
11
|
export { updateSessionRepositoryContext } from "./session-context.js";
|
|
12
|
-
export type { SessionContextRequest } from "./session-context.js";
|
|
12
|
+
export type { SessionContextOutcome, SessionContextRequest, SessionContextRuntime } from "./session-context.js";
|
|
13
13
|
export { runSelectedInteractiveRuntime, selectInteractiveRuntime } from "./runtime-selection.js";
|
|
14
14
|
export type { InteractiveRuntimeRunners, InteractiveRuntimeSelection, OwnedUiProfileId } from "./runtime-selection.js";
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
import { type SessionRepositoryIdentity } from "../../foundation/lifecycle/index.js";
|
|
1
|
+
import { type NativeProcessIdentity, type SessionRepositoryIdentity, type SessionWorktreeInventoryEntry } from "../../foundation/lifecycle/index.js";
|
|
2
2
|
export type SessionContextRequest = {
|
|
3
3
|
readonly action: "link-worktree";
|
|
4
4
|
readonly path: string;
|
|
5
5
|
} | {
|
|
6
6
|
readonly action: "unlink-worktree";
|
|
7
|
+
} | {
|
|
8
|
+
readonly action: "worktrees";
|
|
9
|
+
};
|
|
10
|
+
export type SessionContextOutcome = {
|
|
11
|
+
readonly kind: "linked";
|
|
12
|
+
readonly cwd: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: "unlinked";
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "worktrees";
|
|
17
|
+
readonly entries: readonly SessionWorktreeInventoryEntry[];
|
|
7
18
|
};
|
|
8
|
-
export
|
|
19
|
+
export interface SessionContextRuntime {
|
|
20
|
+
readonly runtimeId: string;
|
|
21
|
+
readonly inspectProcess: (pid: number) => Promise<NativeProcessIdentity | null>;
|
|
22
|
+
}
|
|
23
|
+
export declare function updateSessionRepositoryContext(identity: SessionRepositoryIdentity, request: SessionContextRequest, runtime: SessionContextRuntime): Promise<SessionContextOutcome>;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import { clearSessionRepositoryContext, setSessionRepositoryContext, } from "../../foundation/lifecycle/index.js";
|
|
2
|
-
export async function updateSessionRepositoryContext(identity, request) {
|
|
1
|
+
import { clearSessionRepositoryContext, listSessionRepositoryWorktrees, setSessionRepositoryContext, } from "../../foundation/lifecycle/index.js";
|
|
2
|
+
export async function updateSessionRepositoryContext(identity, request, runtime) {
|
|
3
|
+
const options = { runtimeId: runtime.runtimeId, inspectProcess: runtime.inspectProcess };
|
|
3
4
|
if (request.action === "unlink-worktree") {
|
|
4
|
-
await clearSessionRepositoryContext(identity);
|
|
5
|
-
return
|
|
5
|
+
await clearSessionRepositoryContext(identity, options);
|
|
6
|
+
return { kind: "unlinked" };
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
+
if (request.action === "worktrees") {
|
|
9
|
+
return { kind: "worktrees", entries: await listSessionRepositoryWorktrees(identity, options) };
|
|
10
|
+
}
|
|
11
|
+
return { kind: "linked", cwd: (await setSessionRepositoryContext(identity, request.path, options)).cwd };
|
|
8
12
|
}
|
|
@@ -343,25 +343,27 @@ export class SettingsApp {
|
|
|
343
343
|
this.#apply(menu.entry, value);
|
|
344
344
|
return { consumed: true };
|
|
345
345
|
}
|
|
346
|
-
if (this.#structured !== null) {
|
|
347
|
-
// Invariant: the structured surface is keyboard-only. It owns every pointer report so
|
|
348
|
-
// neither its selection nor the Settings list behind it can react.
|
|
349
|
-
return { consumed: true, render: false };
|
|
350
|
-
}
|
|
351
346
|
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
352
347
|
// Invariant: the whole list pane owns wheel scrolling, including blank space beside
|
|
353
|
-
// short labels.
|
|
348
|
+
// short labels. A fixed structured dialog keeps that content interaction available.
|
|
354
349
|
const screenRow = event.row - 1;
|
|
355
350
|
const wheelBottom = this.#filter === null
|
|
356
351
|
? this.#bodyTopForFrame + this.#bodyHeightForFrame
|
|
357
352
|
: this.#panelTopForFrame + SETTINGS_SEARCH_INPUT_ROWS + SETTINGS_STATUS_ROWS;
|
|
358
|
-
if (screenRow
|
|
353
|
+
if (screenRow >= 0 && screenRow < wheelBottom) {
|
|
354
|
+
const distance = scrollbarWheelRows(this.#scrollbarSpeed());
|
|
355
|
+
if (this.#filter !== null)
|
|
356
|
+
this.#scrollBeforeFilter = null;
|
|
357
|
+
this.#scroll = Math.max(0, this.#scroll + (event.kind === "wheel-down" ? distance : -distance));
|
|
358
|
+
return { consumed: true };
|
|
359
|
+
}
|
|
360
|
+
if (this.#structured === null)
|
|
359
361
|
return { consumed: false };
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
return { consumed: true };
|
|
362
|
+
}
|
|
363
|
+
if (this.#structured !== null) {
|
|
364
|
+
// Invariant: the structured surface is keyboard-only. Non-content-wheel pointer reports
|
|
365
|
+
// cannot change its selection or act on the Settings list behind it.
|
|
366
|
+
return { consumed: true, render: false };
|
|
365
367
|
}
|
|
366
368
|
const rail = this.#railPointer(event);
|
|
367
369
|
if (rail.owned)
|
|
@@ -623,9 +625,7 @@ export class SettingsApp {
|
|
|
623
625
|
const failure = changeFailure(outcome);
|
|
624
626
|
if (failure === null) {
|
|
625
627
|
this.#recordUndo({ kind: "structured", sequence, entry: open.entry, previous, forward });
|
|
626
|
-
this.#notice =
|
|
627
|
-
? `${labelOf(open.entry)} is stored and applies ${applicationLabel(outcome.application)}`
|
|
628
|
-
: null;
|
|
628
|
+
this.#notice = null;
|
|
629
629
|
return;
|
|
630
630
|
}
|
|
631
631
|
// Concurrency: only roll back the dialog if no later press has moved the record on.
|
|
@@ -766,9 +766,7 @@ export class SettingsApp {
|
|
|
766
766
|
// Concurrency: a later press may have moved on; only the last request clears itself.
|
|
767
767
|
if (this.#pending.get(key) === value)
|
|
768
768
|
this.#pending.delete(key);
|
|
769
|
-
this.#notice =
|
|
770
|
-
? `${labelOf(entry)} is stored and applies ${applicationLabel(outcome.application)}`
|
|
771
|
-
: null;
|
|
769
|
+
this.#notice = null;
|
|
772
770
|
});
|
|
773
771
|
}
|
|
774
772
|
#shownValue(entry) {
|
|
@@ -825,9 +823,7 @@ export class SettingsApp {
|
|
|
825
823
|
this.#notice = `Could not restore ${labelOf(record.entry)}: ${failure}`;
|
|
826
824
|
}
|
|
827
825
|
else {
|
|
828
|
-
this.#notice =
|
|
829
|
-
? `${labelOf(record.entry)} is restored and applies ${applicationLabel(outcome.application)}`
|
|
830
|
-
: null;
|
|
826
|
+
this.#notice = null;
|
|
831
827
|
}
|
|
832
828
|
this.#undoActive = false;
|
|
833
829
|
this.#drainUndo();
|
|
@@ -925,7 +921,7 @@ export class SettingsApp {
|
|
|
925
921
|
? CONFIGURE
|
|
926
922
|
: shown === null
|
|
927
923
|
? describeRaw(entry.rawValue)
|
|
928
|
-
:
|
|
924
|
+
: displayValue(shown);
|
|
929
925
|
const range = rangeOf(entry);
|
|
930
926
|
return {
|
|
931
927
|
key,
|
|
@@ -943,6 +939,9 @@ export class SettingsApp {
|
|
|
943
939
|
}
|
|
944
940
|
const state = {
|
|
945
941
|
choices: menu.choices.map(choice => displayValue(choice)),
|
|
942
|
+
...(menu.entry.id === "accentColor" ? {
|
|
943
|
+
previews: menu.choices.map(choice => theme.accentPreview?.(String(choice), "■") ?? ""),
|
|
944
|
+
} : {}),
|
|
946
945
|
current: this.#shownValue(menu.entry) === null ? null : displayValue(this.#shownValue(menu.entry)),
|
|
947
946
|
index: menu.index,
|
|
948
947
|
};
|
|
@@ -1098,23 +1097,6 @@ function displayValue(value) {
|
|
|
1098
1097
|
return value ? "yes" : "no";
|
|
1099
1098
|
return String(value);
|
|
1100
1099
|
}
|
|
1101
|
-
function effectiveDisplay(entry, stored) {
|
|
1102
|
-
const effective = entry.effectiveValue;
|
|
1103
|
-
if (effective === stored)
|
|
1104
|
-
return displayValue(stored);
|
|
1105
|
-
const shownEffective = typeof effective === "string" || typeof effective === "number" || typeof effective === "boolean"
|
|
1106
|
-
? displayValue(effective)
|
|
1107
|
-
: describeRaw(effective);
|
|
1108
|
-
return `${displayValue(stored)} (effective ${shownEffective}; ${applicationLabel(entry.application)})`;
|
|
1109
|
-
}
|
|
1110
|
-
function applicationLabel(application) {
|
|
1111
|
-
switch (application) {
|
|
1112
|
-
case "live": return "live";
|
|
1113
|
-
case "next-session": return "in the next session";
|
|
1114
|
-
case "next-start": return "on the next start";
|
|
1115
|
-
case "current-exit": return "when the current session exits";
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
1100
|
function describeRaw(value) {
|
|
1119
1101
|
if (value === null || value === undefined)
|
|
1120
1102
|
return "unset";
|