@timurproko/a1 0.2.7-dev.820 → 0.2.7-dev.828
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/README.md +7 -1
- package/bin/automatic-update.js +7 -0
- package/bin/tab-launch-context.d.ts +1 -0
- package/bin/tab-launch-context.js +3 -3
- package/bin/ui.js +96 -66
- package/dist/app/session-shell/session-shell-root.d.ts +13 -6
- package/dist/app/session-shell/session-shell-root.js +9 -5
- package/dist/app/session-shell/session-shell.js +68 -18
- package/dist/app/session-shell/shell-host.js +6 -3
- package/dist/app/session-shell/transcript-document.js +1 -1
- package/dist/cli/tabs.d.ts +1 -1
- package/dist/cli/tabs.js +10 -14
- package/dist/composition/owned-settings.d.ts +12 -0
- package/dist/composition/owned-settings.js +36 -0
- package/dist/composition/owned-ui.d.ts +5 -14
- package/dist/composition/owned-ui.js +93 -63
- package/dist/composition/resident-tab-bridge.d.ts +10 -1
- package/dist/composition/resident-tab-bridge.js +21 -0
- package/dist/composition/settings-route-host.d.ts +12 -2
- package/dist/composition/settings-route-host.js +27 -9
- package/dist/composition/settings-search-input.d.ts +9 -0
- package/dist/composition/settings-search-input.js +58 -0
- package/dist/composition/utility-tab.d.ts +28 -0
- package/dist/composition/utility-tab.js +242 -0
- package/dist/contracts/owned-ui/session-backend.d.ts +2 -0
- package/dist/contracts/owned-ui/session-workflows.d.ts +7 -3
- package/dist/contracts/presentation/index.d.ts +11 -0
- package/dist/contracts/presentation/index.js +12 -0
- package/dist/features/launch/development-launch.js +6 -0
- package/dist/features/launch/profile-paths.js +4 -0
- package/dist/features/owned-ui/plus-menu-dialog.d.ts +22 -0
- package/dist/features/owned-ui/plus-menu-dialog.js +76 -0
- package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +6 -8
- package/dist/features/owned-ui/project-trust-prompt.d.ts +1 -0
- package/dist/features/owned-ui/project-trust-prompt.js +7 -3
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +12 -2
- package/dist/features/owned-ui/settings-app.d.ts +10 -3
- package/dist/features/owned-ui/settings-app.js +98 -45
- package/dist/features/owned-ui/settings-search-input.d.ts +29 -0
- package/dist/features/owned-ui/settings-search-input.js +1 -0
- package/dist/features/prompt-history/index.d.ts +1 -1
- package/dist/features/prompt-history/paths.d.ts +2 -1
- package/dist/features/prompt-history/paths.js +10 -2
- package/dist/features/prompt-history/service.d.ts +5 -0
- package/dist/features/prompt-history/service.js +1 -1
- package/dist/features/resident-tab/shortcut-declarations.d.ts +1 -1
- package/dist/features/resident-tab/shortcut-declarations.js +2 -0
- package/dist/foundation/launch-context/index.d.ts +2 -0
- package/dist/foundation/launch-context/index.js +1 -0
- package/dist/foundation/lifecycle/session-repository-context.js +16 -2
- package/dist/foundation/release/automatic-update.d.ts +37 -0
- package/dist/foundation/release/automatic-update.js +265 -0
- package/dist/foundation/release/bootstrap.d.ts +1 -9
- package/dist/foundation/release/bootstrap.js +7 -3
- package/dist/foundation/release/early-accent.d.ts +12 -0
- package/dist/foundation/release/early-accent.js +59 -0
- package/dist/foundation/release/index.d.ts +1 -1
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -2
- package/dist/foundation/release/latest-release.js +1 -1
- package/dist/foundation/release/progress-palette.generated.d.ts +137 -3
- package/dist/foundation/release/progress-palette.generated.js +137 -3
- package/dist/foundation/release/release-gc.js +19 -4
- package/dist/foundation/release/update-execution-lease.d.ts +36 -0
- package/dist/foundation/release/update-execution-lease.js +145 -0
- package/dist/foundation/release/update.d.ts +9 -7
- package/dist/foundation/release/update.js +244 -175
- package/dist/foundation/resident-tabs/bridge-client.d.ts +9 -2
- package/dist/foundation/resident-tabs/bridge-client.js +19 -7
- package/dist/foundation/resident-tabs/maintenance.d.ts +2 -6
- package/dist/foundation/resident-tabs/maintenance.js +5 -23
- package/dist/foundation/resident-tabs/progress-observation-schema.d.ts +34 -0
- package/dist/foundation/resident-tabs/progress-observation-schema.js +1 -0
- package/dist/foundation/resident-tabs/progress-observation.d.ts +3 -6
- package/dist/foundation/resident-tabs/progress-observation.js +43 -12
- package/dist/foundation/resident-tabs/release-holds.js +3 -14
- package/dist/foundation/resident-tabs/routes.d.ts +5 -0
- package/dist/foundation/resident-tabs/routes.js +5 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +2 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +17 -1
- package/dist/integrations/pi/components/modal-frame.js +48 -9
- package/dist/integrations/pi/components/models-dialog.js +4 -52
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +3 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +75 -4
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +57 -37
- package/dist/integrations/pi/components/shell-footer-status.js +19 -3
- package/dist/integrations/pi/components/shell-presenters-transcript.js +4 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +4 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +9 -2
- package/dist/integrations/pi/components/skills-dialog.js +2 -2
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +7 -5
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +15 -8
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -3
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +2 -2
- package/dist/integrations/pi/components/upstream/components/session-footer.js +26 -23
- package/dist/integrations/pi/components/upstream/components/session-selector.js +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +9 -8
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +6 -4
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +8 -8
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +10 -10
- package/dist/integrations/pi/components/upstream/history/editor-core.js +2 -0
- package/dist/integrations/pi/components/upstream/theme/theme.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/theme/theme.js +5 -1
- package/dist/integrations/pi/engine/adapter.js +7 -2
- package/dist/integrations/pi/engine/offline-settings-port.d.ts +23 -0
- package/dist/integrations/pi/engine/offline-settings-port.js +53 -0
- package/dist/integrations/pi/engine/ports.d.ts +1 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/settings-bridge.d.ts +5 -0
- package/dist/integrations/pi/engine/settings-bridge.js +13 -0
- package/dist/integrations/pi/engine/settings-port.js +1 -14
- package/dist/integrations/pi/engine/workflow-runner.js +9 -2
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/product-identity.d.ts +1 -1
- package/dist/product-identity.js +2 -2
- package/dist/product-identity.json +2 -0
- package/dist/ui/apps/host.d.ts +2 -0
- package/dist/ui/apps/host.js +7 -1
- package/dist/ui/components/dialog-panel.js +35 -30
- package/dist/ui/components/line-input.d.ts +3 -0
- package/dist/ui/components/line-input.js +3 -1
- package/dist/ui/components/prompt-input.d.ts +3 -2
- package/dist/ui/components/prompt-input.js +6 -4
- package/dist/ui/components/spans.js +2 -2
- package/dist/ui/components/surface.js +4 -2
- package/dist/ui/components/text.d.ts +3 -6
- package/dist/ui/components/text.js +6 -8
- package/dist/ui/settings/declarations.d.ts +56 -10
- package/dist/ui/settings/declarations.js +38 -9
- package/dist/ui/settings/early-accent.d.ts +81 -0
- package/dist/ui/settings/early-accent.js +50 -0
- package/dist/ui/settings/manager.js +7 -3
- package/dist/ui/settings/migrations.js +15 -0
- package/dist/ui/settings/progress-palette.generated.d.ts +139 -0
- package/dist/ui/settings/progress-palette.generated.js +139 -0
- package/dist/ui/settings/sections.d.ts +4 -0
- package/dist/ui/settings/sections.js +9 -3
- package/docs/architecture/resident-tabs.md +48 -17
- package/docs/architecture/tool-image-presentation.md +2 -1
- package/docs/features/prompt-history.md +41 -20
- package/docs/validation.md +25 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -145,7 +145,13 @@ Stuck on `0.2.2` and `a1 update` fails? Run the installer once, then use `a1 upd
|
|
|
145
145
|
npm x -y -- @timurproko/a1-install
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
The **Update** setting controls the at-most-daily startup check:
|
|
149
|
+
|
|
150
|
+
- **Auto** (default) silently installs a verified update for the running channel, then shows `Update installed · Restart to update`.
|
|
151
|
+
- **Notify** keeps the `Update Available` notice and leaves installation manual.
|
|
152
|
+
- **No** performs no startup update check; updates remain available through the commands above.
|
|
153
|
+
|
|
154
|
+
`A1_SKIP_VERSION_CHECK=1` also disables the startup check. Manual stable, development, and exact-version update commands remain available in every mode.
|
|
149
155
|
|
|
150
156
|
<p align="center"><picture><source media="(prefers-color-scheme: dark)" srcset="docs/assets/readme/separator-dark.svg"><img src="docs/assets/readme/separator.svg" alt="" width="280"></picture></p>
|
|
151
157
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
const TAB_ENVIRONMENT_NAMES = ["A1_TAB_ID", "A1_TAB_TOKEN", "A1_TAB_ENDPOINT"];
|
|
3
|
+
const TAB_ENVIRONMENT_NAMES = ["A1_TAB_ID", "A1_TAB_TOKEN", "A1_TAB_ENDPOINT", "A1_TAB_RELEASE_ID"];
|
|
4
4
|
|
|
5
5
|
/** @param {string} reason */
|
|
6
6
|
export function formatResidentFallbackNotice(reason) {
|
|
@@ -83,12 +83,12 @@ export function consumeTabLaunchContext(arguments_, environment) {
|
|
|
83
83
|
const incarnationArgument = uiArguments.indexOf("--tab-incarnation");
|
|
84
84
|
const tabIncarnation = incarnationArgument === -1 ? undefined : Number(uiArguments[incarnationArgument + 1]);
|
|
85
85
|
if (incarnationArgument !== -1) uiArguments.splice(incarnationArgument, 2);
|
|
86
|
-
const [tabId, token, endpoint] = TAB_ENVIRONMENT_NAMES.map(name => environment[name]);
|
|
86
|
+
const [tabId, token, endpoint, releaseId] = TAB_ENVIRONMENT_NAMES.map(name => environment[name]);
|
|
87
87
|
for (const name of TAB_ENVIRONMENT_NAMES) delete environment[name];
|
|
88
88
|
if (!tabMode) return { uiArguments, tabCredentials: undefined, tabStandby: false };
|
|
89
89
|
if (!tabId || !token || !endpoint || !tabDataDir || tabDataDir.includes("\0")
|
|
90
90
|
|| typeof tabIncarnation !== "number" || !Number.isSafeInteger(tabIncarnation) || tabIncarnation < 1) {
|
|
91
91
|
throw new Error("A1 tab mode requires bridge credentials, recovery directory, and incarnation");
|
|
92
92
|
}
|
|
93
|
-
return { uiArguments, tabCredentials: { tabId, token, endpoint }, tabDataDir, tabIncarnation, tabStandby };
|
|
93
|
+
return { uiArguments, tabCredentials: { tabId, token, endpoint, ...(releaseId === undefined ? {} : { releaseId }) }, tabDataDir, tabIncarnation, tabStandby };
|
|
94
94
|
}
|
package/bin/ui.js
CHANGED
|
@@ -7,6 +7,9 @@ const { uiArguments, tabCredentials, tabDataDir, tabIncarnation, tabStandby } =
|
|
|
7
7
|
// Invariant: one terminal module identity per process, decided before any A1 or Pi module loads.
|
|
8
8
|
const { installPinnedPiTuiResolver } = await import("./module-resolver.js");
|
|
9
9
|
installPinnedPiTuiResolver(new URL("..", import.meta.url).pathname.replace(/^\/(.:)/, "$1").replace(/\/$/, ""));
|
|
10
|
+
const utilityRoute = tabCredentials === undefined
|
|
11
|
+
? null
|
|
12
|
+
: (await import("../dist/foundation/resident-tabs/routes.js")).residentUtilityRoute(tabCredentials.tabId);
|
|
10
13
|
const startup = await import("../dist/foundation/startup/startup-runtime.js");
|
|
11
14
|
startup.enableEnvironmentCompileCache(process.env);
|
|
12
15
|
const { hidesTabSettings, readLaunchContext } = await import("../dist/foundation/launch-context/index.js");
|
|
@@ -32,78 +35,105 @@ const fatal = profile === "a1" ? installFatalExit({
|
|
|
32
35
|
...(launchContext.releaseId === undefined ? {} : { releaseId: launchContext.releaseId }),
|
|
33
36
|
dispose: () => runningApplication?.dispose(),
|
|
34
37
|
}) : undefined;
|
|
35
|
-
const [{ fileURLToPath }, identity
|
|
38
|
+
const [{ fileURLToPath }, identity] = await Promise.all([
|
|
36
39
|
import("node:url"),
|
|
37
40
|
import("./module-identity.js"),
|
|
38
|
-
import("../dist/foundation/startup/startup-descriptor.js"),
|
|
39
41
|
]);
|
|
40
42
|
const packageRootPath = fileURLToPath(new URL("..", import.meta.url));
|
|
41
43
|
identity.configurePinnedPiPublicPackage(packageRootPath);
|
|
42
|
-
// Performance: begin the exact launch graph together while the trace write is pending.
|
|
43
|
-
// Direct owned-module entries avoid evaluating unrelated barrel exports before first paint.
|
|
44
|
-
const modules = descriptor.loadDeclaredStartupGraph();
|
|
45
|
-
await startup.markStartupPhase(process.env, "ui-entry");
|
|
46
|
-
const [
|
|
47
|
-
{ runSelectedInteractiveRuntime },
|
|
48
|
-
{ parseSessionSelection },
|
|
49
|
-
{ createConsoleProjectTrustPrompt },
|
|
50
|
-
{ createConsoleSessionForkPrompt },
|
|
51
|
-
{ runOwnedUi, terminateOwnedUiProcess },
|
|
52
|
-
{ composeOwnedUi },
|
|
53
|
-
] = await modules;
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
// Compatibility: before either composition uses pinned Pi's terminal stack, confirm A1 and Pi
|
|
46
|
+
// resolve it to the same copy so every owned screen shares one module identity.
|
|
47
|
+
const assertPiTuiIdentity = () => identity.assertSinglePiTuiModuleAtLaunch(
|
|
48
|
+
packageRootPath,
|
|
49
|
+
(/** @type {string} */ message) => process.stderr.write(message),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (utilityRoute !== null) {
|
|
53
|
+
if (profile !== "a1" || tabCredentials === undefined) throw new Error("utility tabs require the normal A1 tab profile");
|
|
54
|
+
await startup.markStartupPhase(process.env, "ui-entry");
|
|
55
|
+
assertPiTuiIdentity();
|
|
56
|
+
const utility = await import("../dist/composition/utility-tab.js");
|
|
57
|
+
await startup.markStartupPhase(process.env, "ui-modules-loaded");
|
|
58
|
+
const bridge = new (await import("../dist/foundation/resident-tabs/bridge-client.js")).TabBridgeClient({ credentials: tabCredentials });
|
|
59
|
+
completeRun(utility.runUtilityTab({
|
|
60
|
+
route: utilityRoute,
|
|
61
|
+
bridge,
|
|
62
|
+
cwd: process.cwd(),
|
|
63
|
+
profileId: profile,
|
|
64
|
+
onApplication: application => { runningApplication = application; },
|
|
65
|
+
}), utility.terminateOwnedUiProcess);
|
|
66
|
+
} else {
|
|
67
|
+
const descriptor = await import("../dist/foundation/startup/startup-descriptor.js");
|
|
68
|
+
// Performance: begin the exact Agent launch graph together while the trace write is pending.
|
|
69
|
+
// Direct owned-module entries avoid evaluating unrelated barrel exports before first paint.
|
|
70
|
+
const modules = descriptor.loadDeclaredStartupGraph();
|
|
71
|
+
await startup.markStartupPhase(process.env, "ui-entry");
|
|
72
|
+
const [
|
|
73
|
+
{ runSelectedInteractiveRuntime },
|
|
74
|
+
{ parseSessionSelection },
|
|
75
|
+
{ createConsoleProjectTrustPrompt },
|
|
76
|
+
{ createConsoleSessionForkPrompt },
|
|
77
|
+
{ runOwnedUi, terminateOwnedUiProcess },
|
|
78
|
+
{ composeOwnedUi },
|
|
79
|
+
] = await modules;
|
|
56
80
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
if (tabStandby) await waitForStandbyPromotion(process.stdin, tabDataDir === undefined ? undefined : join(tabDataDir, "standby-promote"));
|
|
82
|
+
assertPiTuiIdentity();
|
|
83
|
+
await startup.markStartupPhase(process.env, "ui-modules-loaded");
|
|
84
|
+
|
|
85
|
+
const sessionSelection = parseSessionSelection(uiArguments);
|
|
86
|
+
completeRun(Promise.resolve().then(async () => {
|
|
87
|
+
const tab = tabCredentials === undefined ? undefined : {
|
|
88
|
+
bridge: new (await import("../dist/foundation/resident-tabs/bridge-client.js")).TabBridgeClient({ credentials: tabCredentials }),
|
|
89
|
+
dataDir: /** @type {string} */ (tabDataDir),
|
|
90
|
+
incarnation: /** @type {number} */ (tabIncarnation),
|
|
91
|
+
};
|
|
92
|
+
if (sessionSelection && profile !== "a1") throw new Error("session selection requires the normal A1 profile");
|
|
93
|
+
return runSelectedInteractiveRuntime(profile, {
|
|
94
|
+
ownedUi: async (profileId, ownedSurfaces) => {
|
|
95
|
+
const processInspector = ownedSurfaces
|
|
96
|
+
? await import("../dist/foundation/process-containment/native-process-inspector.js")
|
|
97
|
+
.then(module => module.createNativeProcessInspector(process.env, process.platform, launchContext.releaseRoot))
|
|
98
|
+
.catch(() => null)
|
|
99
|
+
: null;
|
|
100
|
+
const { application, settings } = await composeOwnedUi({
|
|
101
|
+
cwd: process.cwd(),
|
|
102
|
+
profileId,
|
|
103
|
+
ownedSurfaces,
|
|
104
|
+
notificationVersion: launchContext.updateVersion,
|
|
105
|
+
...(hidesTabSettings(launchContext) ? { hideTabSettings: true } : {}),
|
|
106
|
+
...(processInspector === null ? {} : { inspectProcess: pid => processInspector.observe(pid) }),
|
|
107
|
+
projectTrustPrompt: createConsoleProjectTrustPrompt({ presentation: profile === "a1" ? "bare" : "comparison" }),
|
|
108
|
+
sessionForkPrompt: createConsoleSessionForkPrompt(),
|
|
109
|
+
...(sessionSelection === undefined ? {} : { sessionSelection }),
|
|
110
|
+
...(tab === undefined ? {} : { tab }),
|
|
111
|
+
...(launchContext.residentFallback === undefined ? {} : {
|
|
112
|
+
residentFallbackNotice: formatResidentFallbackNotice(launchContext.residentFallback),
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
runningApplication = application;
|
|
116
|
+
return await runOwnedUi({ application, ...(settings === null ? {} : { settings }) });
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
}), terminateOwnedUiProcess);
|
|
120
|
+
}
|
|
61
121
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
69
|
-
if (sessionSelection && profile !== "a1") throw new Error("session selection requires the normal A1 profile");
|
|
70
|
-
return runSelectedInteractiveRuntime(profile, {
|
|
71
|
-
ownedUi: async (profileId, ownedSurfaces) => {
|
|
72
|
-
const processInspector = ownedSurfaces
|
|
73
|
-
? await import("../dist/foundation/process-containment/native-process-inspector.js")
|
|
74
|
-
.then(module => module.createNativeProcessInspector(process.env, process.platform, launchContext.releaseRoot))
|
|
75
|
-
.catch(() => null)
|
|
76
|
-
: null;
|
|
77
|
-
const { application, settings } = await composeOwnedUi({
|
|
78
|
-
cwd: process.cwd(),
|
|
79
|
-
profileId,
|
|
80
|
-
ownedSurfaces,
|
|
81
|
-
...(hidesTabSettings(launchContext) ? { hideTabSettings: true } : {}),
|
|
82
|
-
...(processInspector === null ? {} : { inspectProcess: pid => processInspector.observe(pid) }),
|
|
83
|
-
projectTrustPrompt: createConsoleProjectTrustPrompt({ presentation: profile === "a1" ? "bare" : "comparison" }),
|
|
84
|
-
sessionForkPrompt: createConsoleSessionForkPrompt(),
|
|
85
|
-
...(sessionSelection === undefined ? {} : { sessionSelection }),
|
|
86
|
-
...(tab === undefined ? {} : { tab }),
|
|
87
|
-
...(launchContext.residentFallback === undefined ? {} : {
|
|
88
|
-
residentFallbackNotice: formatResidentFallbackNotice(launchContext.residentFallback),
|
|
89
|
-
}),
|
|
90
|
-
});
|
|
91
|
-
runningApplication = application;
|
|
92
|
-
return await runOwnedUi({ application, ...(settings === null ? {} : { settings }) });
|
|
122
|
+
/** @param {Promise<number>} run @param {(code: number) => Promise<never>} terminate */
|
|
123
|
+
function completeRun(run, terminate) {
|
|
124
|
+
run.then(
|
|
125
|
+
code => {
|
|
126
|
+
fatal?.remove();
|
|
127
|
+
return terminate(code);
|
|
93
128
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (trustExit) return terminateOwnedUiProcess(error.exitCode);
|
|
106
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
107
|
-
process.exitCode = sessionSelectionError ? error.exitCode : 1;
|
|
108
|
-
},
|
|
109
|
-
);
|
|
129
|
+
error => {
|
|
130
|
+
const sessionSelectionError = error?.name === "PiSessionSelectionError";
|
|
131
|
+
const trustExit = error?.name === "ProjectTrustPromptExitError";
|
|
132
|
+
if (fatal && !sessionSelectionError && !trustExit) { fatal.fail(error); return; }
|
|
133
|
+
fatal?.remove();
|
|
134
|
+
if (trustExit) return terminate(error.exitCode);
|
|
135
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
136
|
+
process.exitCode = sessionSelectionError ? error.exitCode : 1;
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
}
|
|
@@ -116,6 +116,13 @@ export interface OwnedUiShellPresentationOptions {
|
|
|
116
116
|
/** Persistent prompt history: its store, its bound, the editor that recalls it, and the image sidecar. */
|
|
117
117
|
export interface OwnedUiShellHistoryOptions {
|
|
118
118
|
readonly store: import("../../contracts/owned-ui/index.js").PromptHistoryPort;
|
|
119
|
+
/** When present, session replacement selects a new store and sidecar, not the old session's recall. */
|
|
120
|
+
readonly sessionId?: string;
|
|
121
|
+
readonly scope?: "unique" | "shared";
|
|
122
|
+
readonly forSession?: (sessionId: string) => Pick<OwnedUiShellHistoryOptions, "store" | "imageSidecar">;
|
|
123
|
+
/** A live scope change selects the matching store for this session without copying records. */
|
|
124
|
+
readonly forScope?: (scope: "unique" | "shared", sessionId: string | null) => Pick<OwnedUiShellHistoryOptions, "store" | "imageSidecar"> | null;
|
|
125
|
+
readonly onScopeChange?: (listener: (scope: "unique" | "shared") => void) => () => void;
|
|
119
126
|
readonly limit: number;
|
|
120
127
|
readonly editor: import("../../integrations/pi/components/index.js").HistoryEditorConstructor;
|
|
121
128
|
/** Optional per-profile filesystem sidecar for image chip payloads. When present, submit
|
|
@@ -165,19 +172,19 @@ export interface OwnedUiShellSharedServices {
|
|
|
165
172
|
/** What composes an owned session shell, grouped by the collaborator that provides each part. */
|
|
166
173
|
export interface OwnedUiSessionShellOptions {
|
|
167
174
|
readonly engine: OwnedUiShellEngineOptions;
|
|
168
|
-
/**
|
|
175
|
+
/** Resolves selectors and engine-backed transcript renderers. */
|
|
169
176
|
readonly presenters: OwnedUiSessionPresenters;
|
|
170
177
|
readonly presentation?: OwnedUiShellPresentationOptions;
|
|
171
178
|
readonly history?: OwnedUiShellHistoryOptions;
|
|
172
179
|
readonly suggestions?: OwnedUiShellSuggestionOptions;
|
|
173
|
-
/**
|
|
180
|
+
/** Bare A1 only; absent keeps the eight-image comparison limit. */
|
|
174
181
|
readonly promptImages?: OwnedUiShellPromptImagesOptions;
|
|
175
|
-
/**
|
|
182
|
+
/** Bare A1 only; absent keeps pinned per-skill commands. */
|
|
176
183
|
readonly skills?: OwnedUiShellSkillsOptions;
|
|
177
184
|
readonly diagnostics?: OwnedUiShellDiagnosticOptions;
|
|
178
185
|
readonly shared?: OwnedUiShellSharedServices;
|
|
179
186
|
}
|
|
180
|
-
/** Composes
|
|
187
|
+
/** Composes session state into the owned transcript, viewport, editor, and dock. */
|
|
181
188
|
export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
182
189
|
#private;
|
|
183
190
|
readonly editor: PiShellEditorPort;
|
|
@@ -191,7 +198,7 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
191
198
|
readonly requestHyperlinkCleanup?: (rows?: readonly number[]) => void;
|
|
192
199
|
readonly enableDockInputReuse?: boolean;
|
|
193
200
|
readonly persistentHistory?: boolean;
|
|
194
|
-
readonly
|
|
201
|
+
readonly hideUtilityTabCommands?: boolean;
|
|
195
202
|
readonly historyEditor?: import("../../integrations/pi/components/index.js").HistoryEditorConstructor;
|
|
196
203
|
readonly onSubmit: (text: string) => void;
|
|
197
204
|
readonly onPasteRejected?: (error: unknown) => void;
|
|
@@ -217,7 +224,7 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
217
224
|
readonly keybindings?: PiKeybindingsHost;
|
|
218
225
|
readonly promptImageLimit?: () => number;
|
|
219
226
|
readonly skillsPresentation?: () => "collapse" | "expand";
|
|
220
|
-
/**
|
|
227
|
+
/** Resident tab chips already show the session name. */
|
|
221
228
|
readonly footerSessionName?: boolean;
|
|
222
229
|
}, startup?: PiShellHeaderOptions, agentDir?: string, extensionRenderers?: OwnedUiTranscriptRendererPort, sessionLayout?: "pinned" | "custom-viewport", imageAssets?: PiShellImageAssetResolver);
|
|
223
230
|
setEditorPaddingX(padding: number): void;
|
|
@@ -6,7 +6,7 @@ import { progressStatusFrame, progressStatusText } from "../../ui/components/pro
|
|
|
6
6
|
import { createPiQueuedInputStatus, createPiShellFooter, createPiShellHeader, createPiShellLoadedResources, createPiShellStatus, } from "../../integrations/pi/components/shell-footer-status.js";
|
|
7
7
|
import { createPiShellTranscriptComponent, } from "../../integrations/pi/components/shell-presenters-transcript.js";
|
|
8
8
|
import { onPiThemeChange, piTheme } from "../../integrations/pi/components/upstream/theme/theme.js";
|
|
9
|
-
import {} from "../../integrations/pi/components/shell-shared-facade.js";
|
|
9
|
+
import { piShellTruncateToWidth, } from "../../integrations/pi/components/shell-shared-facade.js";
|
|
10
10
|
import {} from "../../integrations/pi/tui-runtime/input-presentation-coordinator.js";
|
|
11
11
|
import { PromptChipStore } from "./prompt-chips.js";
|
|
12
12
|
import { SessionViewportController } from "./session-viewport-controller.js";
|
|
@@ -18,7 +18,7 @@ import { InputSurfaceSwitch } from "./input-surface-switch.js";
|
|
|
18
18
|
import { PinnedLayout } from "./shell-layout.js";
|
|
19
19
|
import { ViewportLayout } from "./viewport-layout.js";
|
|
20
20
|
import { nativeTranscriptLinkColor, TranscriptDocument } from "./transcript-document.js";
|
|
21
|
-
/** Composes
|
|
21
|
+
/** Composes session state into the owned transcript, viewport, editor, and dock. */
|
|
22
22
|
export class OwnedUiSessionShellRoot {
|
|
23
23
|
editor;
|
|
24
24
|
header;
|
|
@@ -128,8 +128,8 @@ export class OwnedUiSessionShellRoot {
|
|
|
128
128
|
this.editor.addToHistory(block.text);
|
|
129
129
|
}
|
|
130
130
|
this.#document.sync(view.transcript);
|
|
131
|
-
// Invariant:
|
|
132
|
-
//
|
|
131
|
+
// Invariant: rendered rows expire when
|
|
132
|
+
// their active theme changes.
|
|
133
133
|
this.#themeUnsubscribe = onPiThemeChange(() => {
|
|
134
134
|
this.invalidate();
|
|
135
135
|
this.#componentRuntime.requestRender(true);
|
|
@@ -607,7 +607,11 @@ export class OwnedUiSessionShellRoot {
|
|
|
607
607
|
return this.#customViewport ? this.#status.renderLive(width) : this.#status.render(width);
|
|
608
608
|
}
|
|
609
609
|
#renderFooter(width) {
|
|
610
|
-
|
|
610
|
+
const footer = this.#extensions.footer ?? this.#footer;
|
|
611
|
+
if (!this.#customViewport)
|
|
612
|
+
return footer.render(width);
|
|
613
|
+
width = Math.max(0, width - 2);
|
|
614
|
+
return footer.render(width).map(row => ` ${piShellTruncateToWidth(row, width)}`);
|
|
611
615
|
}
|
|
612
616
|
#setToolsExpanded(expanded) {
|
|
613
617
|
this.#toolsExpanded = expanded;
|
|
@@ -27,6 +27,12 @@ import { writeSystemClipboardText, } from "./system-clipboard.js";
|
|
|
27
27
|
import { OwnedUiSessionShellRoot, shellResourceEntries, } from "./session-shell-root.js";
|
|
28
28
|
// Invariant: a disposed shell leaves the engine a host that holds no reference back to it.
|
|
29
29
|
const DETACHED_WORKFLOW_INTERACTION = { prompt: async () => null, notify() { } };
|
|
30
|
+
/** Resident Agents refuse the commands their tab bar serves instead, naming where they live. */
|
|
31
|
+
const RESIDENT_UTILITY_TAB_REFUSALS = Object.freeze({
|
|
32
|
+
settings: "Settings is available from the global Settings tab.",
|
|
33
|
+
changelog: "The changelog opens as its own tab from the command palette (Alt+/).",
|
|
34
|
+
name: "Rename the session by renaming its tab (F2).",
|
|
35
|
+
});
|
|
30
36
|
export { OwnedUiSessionShellRoot, } from "./session-shell-root.js";
|
|
31
37
|
export { OwnedUiTerminalHost, sessionTerminalHostOptions } from "./shell-host.js";
|
|
32
38
|
export { formatSessionResumeCommand, quoteCommandArgument } from "./session-lifecycle.js";
|
|
@@ -55,7 +61,7 @@ export class OwnedUiSessionPresenter {
|
|
|
55
61
|
#unsubscribeSkills;
|
|
56
62
|
#installedCommandSignature = "";
|
|
57
63
|
#promptHistory = null;
|
|
58
|
-
#
|
|
64
|
+
#historyBinding;
|
|
59
65
|
#extensionBridge;
|
|
60
66
|
#stop = new SessionStopLatch();
|
|
61
67
|
#dialogs;
|
|
@@ -169,7 +175,7 @@ export class OwnedUiSessionPresenter {
|
|
|
169
175
|
}),
|
|
170
176
|
enableDockInputReuse: inputPresentation?.viewportReuse !== false,
|
|
171
177
|
footerSessionName: options.engine.residentTab === undefined,
|
|
172
|
-
|
|
178
|
+
hideUtilityTabCommands: options.engine.residentTab !== undefined,
|
|
173
179
|
persistentHistory: this.#customViewport && promptHistory !== undefined,
|
|
174
180
|
...(promptHistory === undefined ? {} : { historyEditor: promptHistory.editor }),
|
|
175
181
|
onSubmit: text => { void this.submit(text).catch(() => this.#submission.reportError()); },
|
|
@@ -316,9 +322,10 @@ export class OwnedUiSessionPresenter {
|
|
|
316
322
|
});
|
|
317
323
|
};
|
|
318
324
|
applyViewportSettings();
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
325
|
+
const unsubscribeViewport = this.#customViewport && viewportSettings ? viewportSettings.onChange(settings => this.root.setViewportConfig(settings)) : () => { };
|
|
326
|
+
const unsubscribeHistoryScope = this.#customViewport && promptHistory?.onScopeChange?.(scope => this.#rebindTranscript(scope));
|
|
327
|
+
this.#unsubscribeSettings = () => { unsubscribeViewport(); if (unsubscribeHistoryScope)
|
|
328
|
+
unsubscribeHistoryScope(); };
|
|
322
329
|
constructed.push(this.#unsubscribeSettings);
|
|
323
330
|
this.#unbindSessionSettings = bindSessionSettings(this.backend.settings, initialPiSettings, {
|
|
324
331
|
terminal: this.#terminal,
|
|
@@ -331,8 +338,7 @@ export class OwnedUiSessionPresenter {
|
|
|
331
338
|
}, { customViewport: this.#customViewport });
|
|
332
339
|
constructed.push(this.#unbindSessionSettings);
|
|
333
340
|
if (this.#customViewport && promptHistory !== undefined) {
|
|
334
|
-
this.#
|
|
335
|
-
const sidecar = this.#promptHistoryImageSidecar;
|
|
341
|
+
this.#historyBinding = { options: promptHistory, scope: promptHistory.scope ?? "unique", sessionId: promptHistory.sessionId, imageSidecar: promptHistory.imageSidecar };
|
|
336
342
|
this.#promptHistory = new PromptHistoryController({
|
|
337
343
|
editor: this.root.editor,
|
|
338
344
|
store: promptHistory.store,
|
|
@@ -340,7 +346,7 @@ export class OwnedUiSessionPresenter {
|
|
|
340
346
|
fallback: this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []),
|
|
341
347
|
active: () => this.root.usesDefaultInputSurface(),
|
|
342
348
|
render: () => this.#terminal.requestRender(),
|
|
343
|
-
rehydrate: value => this.root.rehydrateHistoryText(value, id =>
|
|
349
|
+
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
344
350
|
});
|
|
345
351
|
constructed.push(() => { void this.#promptHistory?.close().catch(() => false); });
|
|
346
352
|
}
|
|
@@ -1154,7 +1160,7 @@ export class OwnedUiSessionPresenter {
|
|
|
1154
1160
|
residentTab: this.#resident,
|
|
1155
1161
|
cwd,
|
|
1156
1162
|
promptHistory: () => this.#promptHistory,
|
|
1157
|
-
imageSidecar: () => this.#
|
|
1163
|
+
imageSidecar: () => this.#historyBinding?.imageSidecar,
|
|
1158
1164
|
disposed: () => this.#disposed,
|
|
1159
1165
|
correlation: prefix => this.#correlation(prefix),
|
|
1160
1166
|
lifecycle: () => this.view().lifecycle,
|
|
@@ -1183,13 +1189,57 @@ export class OwnedUiSessionPresenter {
|
|
|
1183
1189
|
this.#resident,
|
|
1184
1190
|
]);
|
|
1185
1191
|
}
|
|
1186
|
-
// Invariant: delivery recovery
|
|
1187
|
-
#rebindTranscript() {
|
|
1188
|
-
|
|
1192
|
+
// Invariant: delivery recovery does not replace a store; conversation or live scope changes can.
|
|
1193
|
+
#rebindTranscript(scope) {
|
|
1194
|
+
const replaced = this.#sessionBindingGeneration !== this.backend.identity.sessionBindingGeneration;
|
|
1195
|
+
if (!replaced && scope === undefined)
|
|
1189
1196
|
return;
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1197
|
+
if (replaced) {
|
|
1198
|
+
this.#sessionBindingGeneration = this.backend.identity.sessionBindingGeneration;
|
|
1199
|
+
this.root.resetTranscript();
|
|
1200
|
+
}
|
|
1201
|
+
const binding = this.#historyBinding;
|
|
1202
|
+
if (binding?.options.forSession !== undefined || binding?.options.forScope !== undefined) {
|
|
1203
|
+
const sessionId = this.backend.identity.currentHistorySessionId();
|
|
1204
|
+
const selectedScope = scope ?? binding.scope;
|
|
1205
|
+
if (selectedScope !== binding.scope || sessionId !== binding.sessionId) {
|
|
1206
|
+
if (!replaced)
|
|
1207
|
+
this.root.editor.recall?.restoreDraft?.();
|
|
1208
|
+
const previous = this.#promptHistory;
|
|
1209
|
+
this.#promptHistory = null;
|
|
1210
|
+
binding.imageSidecar = undefined;
|
|
1211
|
+
binding.scope = selectedScope;
|
|
1212
|
+
binding.sessionId = sessionId ?? undefined;
|
|
1213
|
+
void previous?.close().catch(() => false);
|
|
1214
|
+
const destination = binding.options.forScope !== undefined
|
|
1215
|
+
? binding.options.forScope(selectedScope, sessionId)
|
|
1216
|
+
: sessionId === null ? null : binding.options.forSession(sessionId);
|
|
1217
|
+
if (destination !== null) {
|
|
1218
|
+
binding.imageSidecar = destination.imageSidecar;
|
|
1219
|
+
const controller = new PromptHistoryController({
|
|
1220
|
+
editor: this.root.editor,
|
|
1221
|
+
store: destination.store,
|
|
1222
|
+
limit: binding.options.limit,
|
|
1223
|
+
fallback: replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []) : [],
|
|
1224
|
+
active: () => this.root.usesDefaultInputSurface(),
|
|
1225
|
+
render: () => this.#terminal.requestRender(),
|
|
1226
|
+
rehydrate: value => this.root.rehydrateHistoryText(value, id => this.#historyBinding?.imageSidecar?.readAttachment(id) ?? null),
|
|
1227
|
+
});
|
|
1228
|
+
this.#promptHistory = controller;
|
|
1229
|
+
if (this.#started)
|
|
1230
|
+
controller.start();
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
// Security: missing identity must not reopen Shared or retain another session's recall.
|
|
1234
|
+
const fallback = replaced ? this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []).reverse() : [];
|
|
1235
|
+
this.root.editor.recall?.reset();
|
|
1236
|
+
this.root.editor.recall?.replace(fallback);
|
|
1237
|
+
}
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
if (replaced)
|
|
1242
|
+
this.#promptHistory?.reset(this.view().transcript.flatMap(block => block.kind === "user" ? [block.text] : []));
|
|
1193
1243
|
}
|
|
1194
1244
|
#syncTerminalProgress(view) {
|
|
1195
1245
|
if (!this.#terminal.running)
|
|
@@ -1254,9 +1304,9 @@ export class OwnedUiSessionPresenter {
|
|
|
1254
1304
|
const separator = body.search(/\s/);
|
|
1255
1305
|
const name = separator < 0 ? body : body.slice(0, separator);
|
|
1256
1306
|
const argument = separator < 0 ? "" : body.slice(separator + 1).trimStart();
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1307
|
+
const utilityTab = this.#resident.active ? RESIDENT_UTILITY_TAB_REFUSALS[name] : undefined;
|
|
1308
|
+
if (utilityTab !== undefined)
|
|
1309
|
+
return rejected(utilityTab);
|
|
1260
1310
|
if (this.#dialogs.claimsRoute(name))
|
|
1261
1311
|
return this.#dialogs.openRoute(name);
|
|
1262
1312
|
if (this.#isWorkflowRoute(name))
|
|
@@ -102,10 +102,13 @@ export class OwnedUiTerminalHost {
|
|
|
102
102
|
},
|
|
103
103
|
}),
|
|
104
104
|
} : { layoutRoot: pinnedLayoutRoot(this.#delegatingLayoutParts()) }),
|
|
105
|
-
...(input?.onEvent === undefined ? {} : {
|
|
105
|
+
...(input?.onEvent === undefined && progressObserver === null ? {} : {
|
|
106
106
|
inputDiagnostics: {
|
|
107
|
-
onEvent:
|
|
108
|
-
|
|
107
|
+
onEvent: event => {
|
|
108
|
+
input?.onEvent?.(event);
|
|
109
|
+
progressObserver?.inputPhase?.(event.phase, event.revision);
|
|
110
|
+
},
|
|
111
|
+
...(input?.now === undefined ? {} : { now: input.now }),
|
|
109
112
|
},
|
|
110
113
|
}),
|
|
111
114
|
...(options.terminal === undefined ? {} : { terminal: options.terminal }),
|
|
@@ -260,7 +260,7 @@ export class TranscriptDocument {
|
|
|
260
260
|
: createPiShellChangelog(diagnostic.message).render(width)));
|
|
261
261
|
rows.push(...diagnostics
|
|
262
262
|
.filter(diagnostic => diagnostic.code !== "engine-startup" && diagnostic.code !== "project-trust"
|
|
263
|
-
&& diagnostic.code !== "release-update"
|
|
263
|
+
&& diagnostic.code !== "release-update" && diagnostic.code !== "release-update-installed"
|
|
264
264
|
&& diagnostic.code !== "package-updates" && diagnostic.code !== "changelog-collapsed"
|
|
265
265
|
&& diagnostic.code !== "changelog-expanded")
|
|
266
266
|
.slice(-3)
|
package/dist/cli/tabs.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { runTerminalHostMaintenance, writeDoctorBundle } from "../foundation/res
|
|
|
2
2
|
import type { TabsRequest } from "./tabs-request.js";
|
|
3
3
|
export type { TabsRequest } from "./tabs-request.js";
|
|
4
4
|
export interface TabsCommandOptions {
|
|
5
|
-
/** The
|
|
5
|
+
/** The invoking package, never a different active or retained release. */
|
|
6
6
|
readonly packageRoot?: string;
|
|
7
7
|
readonly environment?: NodeJS.ProcessEnv;
|
|
8
8
|
readonly stdout?: (message: string) => void;
|
package/dist/cli/tabs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveProductPaths } from "../foundation/lifecycle/index.js";
|
|
2
|
-
import {
|
|
2
|
+
import { materializeRelease } from "../foundation/release/index.js";
|
|
3
3
|
import { readResidentTabLaunchSettings, runTerminalHostMaintenance, writeDoctorBundle, } from "../foundation/resident-tabs/index.js";
|
|
4
4
|
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../product-identity.js";
|
|
5
5
|
/** `a1 tabs`: inspect or stop resident tabs without attaching, and never start a host to report state. */
|
|
@@ -9,7 +9,7 @@ export async function runTabsCommand(request, options = {}) {
|
|
|
9
9
|
const stderr = options.stderr ?? (message => process.stderr.write(message));
|
|
10
10
|
const paths = resolveProductPaths(environment);
|
|
11
11
|
const profileRoot = environment[PRODUCT_IDENTITY.environment.profileHome] ?? paths.configDir;
|
|
12
|
-
const releaseRoots = await
|
|
12
|
+
const releaseRoots = await invokingReleaseRoots(paths.dataDir, options.packageRoot, environment);
|
|
13
13
|
const maintenance = options.maintenance ?? runTerminalHostMaintenance;
|
|
14
14
|
const report = await maintenance({
|
|
15
15
|
action: request.action === "doctor" ? "host-status" : request.action,
|
|
@@ -51,22 +51,18 @@ export async function runTabsCommand(request, options = {}) {
|
|
|
51
51
|
}
|
|
52
52
|
return report.exitCode === 0 ? 0 : 1;
|
|
53
53
|
}
|
|
54
|
-
async function
|
|
55
|
-
|
|
54
|
+
async function invokingReleaseRoots(dataDir, packageRoot, environment) {
|
|
55
|
+
if (!packageRoot)
|
|
56
|
+
return [];
|
|
57
|
+
if (environment[PRODUCT_IDENTITY.environment.developmentInstanceId])
|
|
58
|
+
return [packageRoot];
|
|
56
59
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (id && state.releases[id])
|
|
60
|
-
roots.push(state.releases[id].releaseRoot);
|
|
61
|
-
}
|
|
62
|
-
roots.push(...Object.values(state.releases).map(record => record.releaseRoot));
|
|
60
|
+
// Invariant: immutable materialization selects exact payload bytes without activating or starting a host.
|
|
61
|
+
return [(await materializeRelease(packageRoot, dataDir)).releaseRoot];
|
|
63
62
|
}
|
|
64
63
|
catch {
|
|
65
|
-
|
|
64
|
+
return [];
|
|
66
65
|
}
|
|
67
|
-
if (packageRoot)
|
|
68
|
-
roots.push(packageRoot);
|
|
69
|
-
return [...new Set(roots)];
|
|
70
66
|
}
|
|
71
67
|
const NO_TABS = "No resident tabs are running.\n";
|
|
72
68
|
function describe(request, report) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentSettingsPort } from "../contracts/agent-engine/index.js";
|
|
2
|
+
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
3
|
+
export interface OwnedSettingsManagerFactoryOptions {
|
|
4
|
+
readonly profileId: string;
|
|
5
|
+
readonly hideTabSettings?: boolean;
|
|
6
|
+
readonly agent?: AgentSettingsPort | null;
|
|
7
|
+
readonly agentProvider?: () => AgentSettingsPort | null;
|
|
8
|
+
}
|
|
9
|
+
/** Builds the profile-global settings manager shared by the Agent and slim utility compositions. */
|
|
10
|
+
export declare function createOwnedSettingsManager(options: OwnedSettingsManagerFactoryOptions): OwnedSettingsManager;
|
|
11
|
+
/** Rereads the shared settings document whenever its stat changes; returns the stop. */
|
|
12
|
+
export declare function watchSharedSettings(settings: Pick<OwnedSettingsManager, "file" | "refresh">): () => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { unwatchFile, watchFile } from "node:fs";
|
|
2
|
+
import { resolveLaunchProfilePaths } from "../features/launch/profile-paths.js";
|
|
3
|
+
import { resolveProductPaths } from "../foundation/lifecycle/paths.js";
|
|
4
|
+
import { PRODUCT_IDENTITY } from "../product-identity.js";
|
|
5
|
+
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
6
|
+
/** Builds the profile-global settings manager shared by the Agent and slim utility compositions. */
|
|
7
|
+
export function createOwnedSettingsManager(options) {
|
|
8
|
+
const profilePaths = resolveLaunchProfilePaths();
|
|
9
|
+
const productPaths = resolveProductPaths();
|
|
10
|
+
return new OwnedSettingsManager({
|
|
11
|
+
profileDir: profilePaths.agentProfile,
|
|
12
|
+
profileId: options.profileId,
|
|
13
|
+
namespace: PRODUCT_IDENTITY.commandName,
|
|
14
|
+
legacyConfigDir: productPaths.configDir,
|
|
15
|
+
...(options.agent === undefined ? {} : { agent: options.agent }),
|
|
16
|
+
...(options.agentProvider === undefined ? {} : { agentProvider: options.agentProvider }),
|
|
17
|
+
...(options.hideTabSettings ? { hiddenOwnedSettingIds: ["tabsAutoName", "tabsPosition", "tabBarPlusMenu"] } : {}),
|
|
18
|
+
hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
|
|
19
|
+
agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const SHARED_SETTINGS_POLL_MS = 250;
|
|
23
|
+
/** Rereads the shared settings document whenever its stat changes; returns the stop. */
|
|
24
|
+
export function watchSharedSettings(settings) {
|
|
25
|
+
const file = settings.file;
|
|
26
|
+
const listener = () => {
|
|
27
|
+
try {
|
|
28
|
+
settings.refresh();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Compatibility: an unreadable peer write resolves on the next stat change.
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
watchFile(file, { interval: SHARED_SETTINGS_POLL_MS, persistent: false }, listener);
|
|
35
|
+
return () => unwatchFile(file, listener);
|
|
36
|
+
}
|