@timurproko/a1 0.1.8-dev.137 → 0.1.8-dev.151
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 +2 -4
- package/dist/cli/capabilities.d.ts +2 -11
- package/dist/cli/capabilities.js +1 -1
- package/dist/cli/dispatch.js +3 -6
- package/dist/composition/owned-ui.js +26 -5
- package/dist/composition/settings-route-host.d.ts +1 -1
- package/dist/composition/settings-route-host.js +1 -1
- package/dist/contracts/owned-ui/model.d.ts +28 -0
- package/dist/contracts/owned-ui/validation.js +14 -0
- package/dist/features/launch/development-launch.js +11 -3
- package/dist/features/launch/index.d.ts +0 -1
- package/dist/features/launch/index.js +0 -1
- package/dist/features/launch/intent.d.ts +3 -2
- package/dist/features/launch/intent.js +1 -2
- package/dist/features/launch/prepare-launch.d.ts +0 -2
- package/dist/features/launch/prepare-launch.js +2 -9
- package/dist/features/launch/profile-paths.d.ts +1 -2
- package/dist/features/launch/profile-paths.js +2 -8
- package/dist/features/launch/runtime-selection.d.ts +2 -5
- package/dist/features/owned-ui/settings-app.js +38 -14
- package/dist/foundation/lifecycle/model.d.ts +1 -1
- package/dist/foundation/lifecycle/model.js +1 -1
- package/dist/foundation/release/bootstrap.d.ts +1 -3
- package/dist/foundation/release/bootstrap.js +1 -1
- package/dist/foundation/storage/control-store.js +37 -3
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +55 -0
- package/dist/integrations/pi/components/owned-editor-ux.js +778 -0
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +44 -6
- package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
- package/dist/integrations/pi/components/shell-footer-status.js +14 -5
- package/dist/integrations/pi/components/shell-presenters-transcript.d.ts +3 -2
- package/dist/integrations/pi/components/shell-presenters-transcript.js +9 -8
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +41 -7
- package/dist/integrations/pi/components/shell-shared-facade.js +3 -1
- package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +13 -0
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +27 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +36 -3
- package/dist/integrations/pi/engine/adapter.js +21 -3
- package/dist/integrations/pi/engine/session-integration.d.ts +2 -1
- package/dist/integrations/pi/engine/session-integration.js +17 -3
- package/dist/integrations/pi/session-ui/prompt-chips.d.ts +23 -0
- package/dist/integrations/pi/session-ui/prompt-chips.js +242 -0
- package/dist/integrations/pi/session-ui/route-host.d.ts +5 -0
- package/dist/integrations/pi/{owned-ui → session-ui}/session-shell-root.d.ts +34 -5
- package/dist/integrations/pi/{owned-ui → session-ui}/session-shell-root.js +294 -45
- package/dist/integrations/pi/{owned-ui → session-ui}/session-shell.d.ts +1 -1
- package/dist/integrations/pi/{owned-ui → session-ui}/session-shell.js +167 -24
- package/dist/integrations/pi/session-ui/session-viewport-controller.d.ts +39 -0
- package/dist/integrations/pi/session-ui/session-viewport-controller.js +369 -0
- package/dist/integrations/pi/session-ui/system-clipboard.d.ts +11 -0
- package/dist/integrations/pi/session-ui/system-clipboard.js +101 -0
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -1
- package/dist/integrations/pi/tui-runtime/adapter.js +51 -2
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +4 -6
- 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 +3 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/product-identity.d.ts +2 -2
- package/dist/product-identity.js +3 -4
- package/dist/product-identity.json +3 -5
- package/dist/ui/apps/contracts.d.ts +23 -1
- package/dist/ui/apps/host.js +9 -1
- package/dist/ui/components/index.d.ts +3 -0
- package/dist/ui/components/index.js +3 -0
- package/dist/ui/components/mouse.d.ts +10 -0
- package/dist/ui/components/mouse.js +23 -0
- package/dist/ui/components/prompt-row.d.ts +14 -0
- package/dist/ui/components/prompt-row.js +20 -0
- package/dist/ui/components/scrollbar.d.ts +26 -0
- package/dist/ui/components/scrollbar.js +35 -0
- package/dist/ui/components/spans.d.ts +21 -0
- package/dist/ui/components/spans.js +178 -0
- package/dist/ui/components/submitted-prompt.d.ts +23 -0
- package/dist/ui/components/submitted-prompt.js +50 -0
- package/dist/ui/components/text-selection.d.ts +53 -0
- package/dist/ui/components/text-selection.js +168 -0
- package/dist/ui/components/text.d.ts +14 -0
- package/dist/ui/components/text.js +40 -0
- package/dist/ui/components/transcript-viewport.d.ts +104 -0
- package/dist/ui/components/transcript-viewport.js +381 -0
- package/dist/ui/settings/declarations.d.ts +8 -1
- package/dist/ui/settings/declarations.js +33 -5
- package/dist/ui/settings/migrations.d.ts +1 -1
- package/dist/ui/settings/migrations.js +21 -2
- package/dist/ui/settings/sections.js +15 -8
- package/dist/ui/settings/session.d.ts +2 -0
- package/dist/ui/settings/session.js +7 -5
- package/docs/architecture/boundaries.md +3 -3
- package/docs/architecture/project-structure.md +2 -2
- package/docs/architecture/resource-and-data-policy.md +1 -1
- package/docs/architecture/toolchain.md +5 -5
- package/docs/architecture/ui-reference-provenance.md +11 -2
- package/docs/features/launch-profiles.md +7 -14
- package/docs/manual-launch-instance-acceptance.md +12 -35
- package/docs/manual-owned-ui-checkpoint.md +2 -3
- package/docs/manual-pi-boundary-candidate.md +4 -5
- package/package.json +4 -2
- package/dist/features/launch/profiles.d.ts +0 -12
- package/dist/features/launch/profiles.js +0 -26
- package/dist/integrations/pi/owned-ui/route-host.d.ts +0 -29
- /package/dist/integrations/pi/{owned-ui → session-ui}/index.d.ts +0 -0
- /package/dist/integrations/pi/{owned-ui → session-ui}/index.js +0 -0
- /package/dist/integrations/pi/{owned-ui → session-ui}/route-host.js +0 -0
package/README.md
CHANGED
|
@@ -31,17 +31,16 @@ a1 update:107 # install numbered preview 107
|
|
|
31
31
|
a1 update --models # refresh A1's model catalogs
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Development previews add
|
|
34
|
+
Development previews add the Pi comparison profile; release builds do not carry it.
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
37
|
a1 pi # vanilla Pi oracle: ~/.pi/agent
|
|
38
|
-
a1 sandbox # isolated vanilla Pi profile: ~/.a1/sandbox
|
|
39
38
|
```
|
|
40
39
|
|
|
41
40
|
## Extensions
|
|
42
41
|
|
|
43
42
|
Pi extension packages install into A1's own profile (`~/.a1/agent`), so bare `a1`
|
|
44
|
-
loads them and `a1 pi`
|
|
43
|
+
loads them and `a1 pi` does not. Sources are Pi's: `npm:`, git, or a
|
|
45
44
|
local path.
|
|
46
45
|
|
|
47
46
|
```sh
|
|
@@ -63,7 +62,6 @@ npm ci # install exact locked dependencies
|
|
|
63
62
|
npm run build # compile TypeScript and the process guardian into dist
|
|
64
63
|
npm start # build and launch a development `a1`
|
|
65
64
|
npm run start:pi # build and launch a development `a1 pi`
|
|
66
|
-
npm run start:sandbox # build and launch a development `a1 sandbox`
|
|
67
65
|
npm run test:fast # typecheck + fast suite (alias: npm test)
|
|
68
66
|
npm run test:full # complete non-physical suite
|
|
69
67
|
```
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `pi` and `sandbox` exist to compare A1 against pinned Pi and to try resources
|
|
3
|
-
* against an isolated profile. Both are development instruments rather than
|
|
4
|
-
* product, so a stable release does not carry them: what a released `a1` exposes
|
|
5
|
-
* is the product plus its maintenance and package commands.
|
|
6
|
-
*
|
|
7
|
-
* Which build this is comes from its own version. A prerelease version is a
|
|
8
|
-
* `next`-channel build, which is where that work happens; a release version is
|
|
9
|
-
* not. Nothing to configure, and no way for a released build to be talked into it.
|
|
10
|
-
*/
|
|
1
|
+
/** The Pi comparison launch is a prerelease development instrument, not product. */
|
|
11
2
|
export interface CliCapabilities {
|
|
12
|
-
readonly
|
|
3
|
+
readonly developmentComparison: boolean;
|
|
13
4
|
}
|
|
14
5
|
export declare function cliCapabilities(version: string): CliCapabilities;
|
|
15
6
|
export declare function isPrereleaseVersion(version: string): boolean;
|
package/dist/cli/capabilities.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { prerelease } from "semver";
|
|
2
2
|
export function cliCapabilities(version) {
|
|
3
|
-
return Object.freeze({
|
|
3
|
+
return Object.freeze({ developmentComparison: isPrereleaseVersion(version) });
|
|
4
4
|
}
|
|
5
5
|
export function isPrereleaseVersion(version) {
|
|
6
6
|
return (prerelease(version)?.length ?? 0) > 0;
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -3,7 +3,7 @@ import { PRODUCT_TEXT } from "../product-identity.js";
|
|
|
3
3
|
export function cliUsage(capabilities) {
|
|
4
4
|
return PRODUCT_TEXT.usage([
|
|
5
5
|
"",
|
|
6
|
-
...(capabilities.
|
|
6
|
+
...(capabilities.developmentComparison ? ["pi"] : []),
|
|
7
7
|
"version",
|
|
8
8
|
"update [self|--models]",
|
|
9
9
|
"update:develop",
|
|
@@ -14,7 +14,7 @@ export function cliUsage(capabilities) {
|
|
|
14
14
|
"pi update [--extensions|<source>]",
|
|
15
15
|
]);
|
|
16
16
|
}
|
|
17
|
-
const PROFILE_WORDS = new Set(["pi"
|
|
17
|
+
const PROFILE_WORDS = new Set(["pi"]);
|
|
18
18
|
export async function dispatchCli(arguments_, handlers, output, capabilities) {
|
|
19
19
|
const command = parseCliCommand(arguments_, capabilities);
|
|
20
20
|
if (command.kind === "error") {
|
|
@@ -36,12 +36,9 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
36
36
|
if (command === "pi") {
|
|
37
37
|
if (rest.length > 0)
|
|
38
38
|
return parsePiPackageCommand(rest);
|
|
39
|
-
if (capabilities.
|
|
39
|
+
if (capabilities.developmentComparison)
|
|
40
40
|
return { kind: "launch", profileId: "pi" };
|
|
41
41
|
}
|
|
42
|
-
if (capabilities.developmentProfiles && command === "sandbox") {
|
|
43
|
-
return withoutArguments(rest, { kind: "launch", profileId: command });
|
|
44
|
-
}
|
|
45
42
|
if (command === "version")
|
|
46
43
|
return withoutArguments(rest, { kind: "version" });
|
|
47
44
|
if (command !== undefined && command.startsWith("update:"))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveProductPaths } from "../foundation/lifecycle/index.js";
|
|
2
2
|
import { applyConfiguredPiTheme, getAvailablePiThemes } from "../integrations/pi/components/index.js";
|
|
3
3
|
import { createPiEngineAdapter } from "../integrations/pi/engine/index.js";
|
|
4
|
-
import { OwnedUiSessionShell } from "../integrations/pi/
|
|
4
|
+
import { OwnedUiSessionShell } from "../integrations/pi/session-ui/index.js";
|
|
5
5
|
import { OwnedUiSettingsSession, OwnedUiSettingsStore } from "../ui/settings/index.js";
|
|
6
6
|
import { createPiTerminalBridge } from "../integrations/pi/tui-runtime/index.js";
|
|
7
7
|
import { createOwnedRouteHost } from "./settings-route-host.js";
|
|
@@ -13,21 +13,32 @@ export async function composeOwnedUi(options = {}) {
|
|
|
13
13
|
const adapter = options.createPiAdapter
|
|
14
14
|
? await options.createPiAdapter()
|
|
15
15
|
: await createPiEngineAdapter({ cwd, availableThemes: () => getAvailablePiThemes().map(theme => theme.name) });
|
|
16
|
+
const ownedSurfaces = options.ownedSurfaces !== "off";
|
|
16
17
|
const settings = options.profileId === undefined
|
|
17
18
|
? null
|
|
18
19
|
: new OwnedUiSettingsSession({
|
|
19
20
|
store: new OwnedUiSettingsStore({ configDir: resolveProductPaths().configDir, profileId: options.profileId }),
|
|
20
21
|
agentProvider: () => adapter.settingsPort(),
|
|
22
|
+
...(ownedSurfaces ? {
|
|
23
|
+
hiddenAgentSettingIds: ["tuiMode", "theme", "fullscreenScrollbar", "quietStartup"],
|
|
24
|
+
} : {}),
|
|
21
25
|
});
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
// Bare A1 intentionally ships one visual target while its UI is being completed:
|
|
27
|
+
// dark, regardless of terminal detection or a previously stored Pi theme. The
|
|
28
|
+
// comparison profile keeps Pi's configured theme behavior and settings surface.
|
|
29
|
+
applyConfiguredPiTheme(ownedSurfaces ? "dark" : adapter.configuredTheme());
|
|
30
|
+
const routeHost = settings === null || !ownedSurfaces ? null : createOwnedRouteHost(settings);
|
|
31
|
+
const viewportSettings = settings === null || !ownedSurfaces ? null : {
|
|
32
|
+
snapshot: () => viewportSettingsSnapshot(settings),
|
|
33
|
+
onChange: listener => settings.onChange(() => listener(viewportSettingsSnapshot(settings))),
|
|
34
|
+
};
|
|
26
35
|
const shell = new OwnedUiSessionShell({
|
|
27
36
|
backend: adapter,
|
|
28
37
|
cwd,
|
|
29
38
|
...(options.terminal === undefined ? {} : { terminal: createPiTerminalBridge(options.terminal) }),
|
|
30
39
|
...(routeHost === null ? {} : { routeHost }),
|
|
40
|
+
...(ownedSurfaces ? { sessionLayout: "custom-viewport" } : {}),
|
|
41
|
+
...(viewportSettings === null ? {} : { viewportSettings }),
|
|
31
42
|
});
|
|
32
43
|
const application = {
|
|
33
44
|
get disposed() { return adapter.disposed; },
|
|
@@ -38,3 +49,13 @@ export async function composeOwnedUi(options = {}) {
|
|
|
38
49
|
};
|
|
39
50
|
return { application, settings };
|
|
40
51
|
}
|
|
52
|
+
function viewportSettingsSnapshot(settings) {
|
|
53
|
+
const appearance = settings.value("scrollbarAppearance");
|
|
54
|
+
const style = settings.value("scrollbarStyle");
|
|
55
|
+
const speed = settings.value("scrollbarSpeed");
|
|
56
|
+
return {
|
|
57
|
+
scrollbarAppearance: appearance === "always" || appearance === "hidden" ? appearance : "auto",
|
|
58
|
+
scrollbarStyle: style === "thick" ? "thick" : "thin",
|
|
59
|
+
scrollbarSpeed: speed === "high" ? "high" : speed === "fast" ? "fast" : "normal",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { UiRouteHost } from "../integrations/pi/owned-ui/index.js";
|
|
2
1
|
import type { OwnedUiSettingsSession } from "../ui/settings/index.js";
|
|
2
|
+
import { type UiRouteHost } from "../ui/apps/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Registers the A1-owned screens and adapts the app host to the shell's route
|
|
5
5
|
* seam. The shell mounts whatever surface it is handed and forwards keys; it
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SETTINGS_APP_ID, SETTINGS_ROUTE, SettingsApp } from "../features/owned-ui/index.js";
|
|
2
2
|
import { piTheme } from "../integrations/pi/components/index.js";
|
|
3
|
-
import { UiAppHost, UiAppRegistry } from "../ui/apps/index.js";
|
|
3
|
+
import { UiAppHost, UiAppRegistry, } from "../ui/apps/index.js";
|
|
4
4
|
import { faint } from "../ui/components/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* Registers the A1-owned screens and adapts the app host to the shell's route
|
|
@@ -12,12 +12,28 @@ export interface OwnedUiModelInfo {
|
|
|
12
12
|
readonly displayName: string;
|
|
13
13
|
}
|
|
14
14
|
export type OwnedUiThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
15
|
+
export interface OwnedUiViewportSettings {
|
|
16
|
+
readonly scrollbarAppearance: "auto" | "always" | "hidden";
|
|
17
|
+
readonly scrollbarStyle: "thin" | "thick";
|
|
18
|
+
/** normal is baseline; fast is 2x normal; high is normal plus fast. */
|
|
19
|
+
readonly scrollbarSpeed: "normal" | "fast" | "high";
|
|
20
|
+
}
|
|
21
|
+
/** Narrow live settings boundary consumed by the bare-A1 shell composition. */
|
|
22
|
+
export interface OwnedUiViewportSettingsPort {
|
|
23
|
+
snapshot(): OwnedUiViewportSettings;
|
|
24
|
+
onChange(listener: (settings: OwnedUiViewportSettings) => void): () => void;
|
|
25
|
+
}
|
|
15
26
|
export interface OwnedUiTerminalSurface {
|
|
16
27
|
readonly columns: number;
|
|
17
28
|
readonly rows: number;
|
|
18
29
|
readonly focusedRegion: "transcript" | "editor" | "dialog" | "overlay" | "status";
|
|
19
30
|
readonly hardwareCursor: boolean;
|
|
20
31
|
}
|
|
32
|
+
export interface OwnedUiImageAttachment {
|
|
33
|
+
readonly type: "image";
|
|
34
|
+
readonly data: string;
|
|
35
|
+
readonly mimeType: string;
|
|
36
|
+
}
|
|
21
37
|
export interface OwnedUiEditorState {
|
|
22
38
|
readonly text: string;
|
|
23
39
|
readonly queuedSubmissions: readonly string[];
|
|
@@ -122,11 +138,13 @@ export type OwnedUiCommand = {
|
|
|
122
138
|
readonly correlationId: OwnedUiCorrelationId;
|
|
123
139
|
readonly sessionId: OwnedUiSessionId;
|
|
124
140
|
readonly text: string;
|
|
141
|
+
readonly images?: readonly OwnedUiImageAttachment[];
|
|
125
142
|
} | {
|
|
126
143
|
readonly type: "steer" | "follow-up";
|
|
127
144
|
readonly correlationId: OwnedUiCorrelationId;
|
|
128
145
|
readonly sessionId: OwnedUiSessionId;
|
|
129
146
|
readonly text: string;
|
|
147
|
+
readonly images?: readonly OwnedUiImageAttachment[];
|
|
130
148
|
} | {
|
|
131
149
|
readonly type: "abort" | "retry" | "compact" | "shutdown";
|
|
132
150
|
readonly correlationId: OwnedUiCorrelationId;
|
|
@@ -189,6 +207,16 @@ export type OwnedUiEvent = {
|
|
|
189
207
|
readonly sessionId: OwnedUiSessionId;
|
|
190
208
|
readonly sequence: number;
|
|
191
209
|
readonly block: OwnedUiTranscriptBlock;
|
|
210
|
+
} | {
|
|
211
|
+
/** One completed assistant reply; never a tool row or transcript rebuild. */
|
|
212
|
+
readonly type: "assistant-message-completed";
|
|
213
|
+
readonly sessionId: OwnedUiSessionId;
|
|
214
|
+
readonly sequence: number;
|
|
215
|
+
} | {
|
|
216
|
+
/** A fresh agent run has started, used by follow-mode surfaces. */
|
|
217
|
+
readonly type: "agent-run-started";
|
|
218
|
+
readonly sessionId: OwnedUiSessionId;
|
|
219
|
+
readonly sequence: number;
|
|
192
220
|
} | {
|
|
193
221
|
readonly type: "editor-state";
|
|
194
222
|
readonly sessionId: OwnedUiSessionId;
|
|
@@ -5,6 +5,8 @@ const MAX_MESSAGE_LENGTH = 4_096;
|
|
|
5
5
|
const MAX_TEXT_BYTES = 256 * 1024;
|
|
6
6
|
const MAX_PAYLOAD_BYTES = 64 * 1024;
|
|
7
7
|
const MAX_SESSION_VIEW_BYTES = 1024 * 1024;
|
|
8
|
+
const MAX_IMAGE_DATA_BYTES = 8 * 1024 * 1024;
|
|
9
|
+
const MAX_PROMPT_IMAGES = 8;
|
|
8
10
|
const MAX_BLOCKS = 10_000;
|
|
9
11
|
const MAX_CUSTOMIZATIONS = 1_000;
|
|
10
12
|
const MAX_DIAGNOSTICS = 1_000;
|
|
@@ -53,6 +55,15 @@ export function assertOwnedUiCommand(command) {
|
|
|
53
55
|
case "steer":
|
|
54
56
|
case "follow-up":
|
|
55
57
|
assertBoundedText(command.text, "owned-UI prompt text", MAX_TEXT_BYTES);
|
|
58
|
+
if (command.images !== undefined) {
|
|
59
|
+
assertCollection(command.images, "owned-UI prompt images", MAX_PROMPT_IMAGES);
|
|
60
|
+
for (const image of command.images) {
|
|
61
|
+
if (image.type !== "image")
|
|
62
|
+
throw new TypeError("owned-UI prompt image type is invalid");
|
|
63
|
+
assertBoundedText(image.data, "owned-UI prompt image data", MAX_IMAGE_DATA_BYTES);
|
|
64
|
+
assertBoundedText(image.mimeType, "owned-UI prompt image MIME type", MAX_LABEL_LENGTH);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
56
67
|
return;
|
|
57
68
|
case "abort":
|
|
58
69
|
case "retry":
|
|
@@ -103,6 +114,9 @@ export function assertOwnedUiEvent(event) {
|
|
|
103
114
|
case "transcript-block":
|
|
104
115
|
assertOwnedUiTranscriptBlock(event.block);
|
|
105
116
|
return;
|
|
117
|
+
case "assistant-message-completed":
|
|
118
|
+
case "agent-run-started":
|
|
119
|
+
return;
|
|
106
120
|
case "editor-state":
|
|
107
121
|
assertOwnedUiEditorState(event.editor);
|
|
108
122
|
return;
|
|
@@ -8,8 +8,16 @@ export function resolveDevelopmentLaunchEnvironment(canonicalPackageRoot, releas
|
|
|
8
8
|
const instanceId = selectedInstanceId
|
|
9
9
|
? createHash("sha256").update(selectedInstanceId).digest("hex").slice(0, 16)
|
|
10
10
|
: randomUUID().replaceAll("-", "").slice(0, 16);
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
const checkoutRoot = resolve(temporaryDirectory, PRODUCT_IDENTITY.state.developmentDirectory, checkoutId);
|
|
12
|
+
const selectedDevelopmentRoot = source[PRODUCT_IDENTITY.environment.developmentRoot];
|
|
13
|
+
const developmentRoot = resolve(selectedDevelopmentRoot
|
|
14
|
+
?? join(checkoutRoot, releaseId, "instances", instanceId));
|
|
15
|
+
// Runtime/data remain instance-isolated, but product settings are user
|
|
16
|
+
// preferences and must survive a fresh local launch (and a rebuilt candidate).
|
|
17
|
+
// An explicit development root retains its historical self-contained policy.
|
|
18
|
+
const persistentConfigDir = selectedDevelopmentRoot
|
|
19
|
+
? join(developmentRoot, "config")
|
|
20
|
+
: join(checkoutRoot, "config");
|
|
13
21
|
const dataDir = resolve(source[PRODUCT_IDENTITY.environment.dataDir] ?? join(developmentRoot, "data"));
|
|
14
22
|
return {
|
|
15
23
|
checkoutId,
|
|
@@ -19,7 +27,7 @@ export function resolveDevelopmentLaunchEnvironment(canonicalPackageRoot, releas
|
|
|
19
27
|
environment: {
|
|
20
28
|
...source,
|
|
21
29
|
[PRODUCT_IDENTITY.environment.developmentInstanceId]: instanceId,
|
|
22
|
-
[PRODUCT_IDENTITY.environment.configDir]: resolve(source[PRODUCT_IDENTITY.environment.configDir] ??
|
|
30
|
+
[PRODUCT_IDENTITY.environment.configDir]: resolve(source[PRODUCT_IDENTITY.environment.configDir] ?? persistentConfigDir),
|
|
23
31
|
[PRODUCT_IDENTITY.environment.dataDir]: dataDir,
|
|
24
32
|
[PRODUCT_IDENTITY.environment.runtimeDir]: resolve(source[PRODUCT_IDENTITY.environment.runtimeDir] ?? join(developmentRoot, "runtime")),
|
|
25
33
|
[PRODUCT_IDENTITY.environment.databasePath]: resolve(source[PRODUCT_IDENTITY.environment.databasePath] ?? join(dataDir, PRODUCT_IDENTITY.endpoint.databaseFilename)),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
2
|
+
export type { LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
2
3
|
export interface InteractiveLaunchIntent {
|
|
3
4
|
readonly kind: "interactive";
|
|
4
|
-
readonly
|
|
5
|
+
readonly profileId: LaunchProfileId;
|
|
5
6
|
}
|
|
6
7
|
export type LaunchIntent = InteractiveLaunchIntent;
|
|
7
8
|
export declare function interactiveLaunchIntent(profileId: LaunchProfileId): InteractiveLaunchIntent;
|
|
@@ -2,9 +2,7 @@ import { type LaunchProfilePathOptions } from "./profile-paths.js";
|
|
|
2
2
|
import { initializeProductProfile } from "./initialize-profile.js";
|
|
3
3
|
import type { InteractiveLaunchIntent } from "./intent.js";
|
|
4
4
|
export interface PreparedInteractiveLaunch {
|
|
5
|
-
readonly intent: InteractiveLaunchIntent;
|
|
6
5
|
readonly environment: NodeJS.ProcessEnv;
|
|
7
|
-
readonly piArguments: readonly string[];
|
|
8
6
|
readonly configurationRoot: string | null;
|
|
9
7
|
}
|
|
10
8
|
export interface PrepareInteractiveLaunchOptions extends LaunchProfilePathOptions {
|
|
@@ -2,7 +2,7 @@ import { configurationRootForProfile, resolveLaunchProfilePaths } from "./profil
|
|
|
2
2
|
import { initializeProductProfile } from "./initialize-profile.js";
|
|
3
3
|
export async function prepareInteractiveLaunch(intent, environment = process.env, options = {}) {
|
|
4
4
|
const paths = resolveLaunchProfilePaths({ ...options, environment });
|
|
5
|
-
const configurationRoot = configurationRootForProfile(intent.
|
|
5
|
+
const configurationRoot = configurationRootForProfile(intent.profileId, paths);
|
|
6
6
|
if (configurationRoot !== null)
|
|
7
7
|
await (options.initializeProfile ?? initializeProductProfile)(configurationRoot);
|
|
8
8
|
const childEnvironment = { ...environment };
|
|
@@ -10,12 +10,5 @@ export async function prepareInteractiveLaunch(intent, environment = process.env
|
|
|
10
10
|
delete childEnvironment.PI_CODING_AGENT_DIR;
|
|
11
11
|
else
|
|
12
12
|
childEnvironment.PI_CODING_AGENT_DIR = configurationRoot;
|
|
13
|
-
|
|
14
|
-
childEnvironment.A1_LAUNCH_ARGUMENTS_JSON = JSON.stringify(piArguments);
|
|
15
|
-
return Object.freeze({
|
|
16
|
-
intent,
|
|
17
|
-
environment: childEnvironment,
|
|
18
|
-
piArguments: Object.freeze(piArguments),
|
|
19
|
-
configurationRoot,
|
|
20
|
-
});
|
|
13
|
+
return Object.freeze({ environment: childEnvironment, configurationRoot });
|
|
21
14
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type { LaunchProfileId } from "./
|
|
1
|
+
import type { LaunchProfileId } from "./intent.js";
|
|
2
2
|
export interface LaunchProfilePaths {
|
|
3
3
|
readonly home: string;
|
|
4
4
|
readonly managedStateRoot: string;
|
|
5
5
|
readonly agentProfile: string;
|
|
6
|
-
readonly sandbox: string;
|
|
7
6
|
}
|
|
8
7
|
export interface LaunchProfilePathOptions {
|
|
9
8
|
readonly environment?: NodeJS.ProcessEnv;
|
|
@@ -7,20 +7,14 @@ export function resolveLaunchProfilePaths(options = {}) {
|
|
|
7
7
|
const selectedHome = options.home ?? environment[PRODUCT_IDENTITY.environment.profileHome] ?? options.readHome?.() ?? homedir();
|
|
8
8
|
const home = validateAbsolutePath(selectedHome, "effective user home", path);
|
|
9
9
|
const agentProfile = path.resolve(home, PRODUCT_IDENTITY.state.piAgentProfile);
|
|
10
|
-
const managedStateRoot = path.dirname(agentProfile);
|
|
11
10
|
return Object.freeze({
|
|
12
11
|
home,
|
|
13
|
-
managedStateRoot,
|
|
12
|
+
managedStateRoot: path.dirname(agentProfile),
|
|
14
13
|
agentProfile,
|
|
15
|
-
sandbox: path.resolve(home, PRODUCT_IDENTITY.state.piSandboxProfile),
|
|
16
14
|
});
|
|
17
15
|
}
|
|
18
16
|
export function configurationRootForProfile(profileId, paths) {
|
|
19
|
-
|
|
20
|
-
return paths.agentProfile;
|
|
21
|
-
if (profileId === "sandbox")
|
|
22
|
-
return paths.sandbox;
|
|
23
|
-
return null;
|
|
17
|
+
return profileId === "a1" ? paths.agentProfile : null;
|
|
24
18
|
}
|
|
25
19
|
function validateAbsolutePath(value, name, path) {
|
|
26
20
|
if (value.length === 0 || value.includes("\0"))
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { type LaunchProfileId } from "../../foundation/lifecycle/index.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* bare `a1` is the product, while `a1 pi` and `a1 sandbox` present pinned Pi's
|
|
6
|
-
* interface and nothing of A1's own, against Pi's own profile and against an
|
|
7
|
-
* isolated one.
|
|
3
|
+
* Both interactive commands use the owned composition. Bare A1 enables product
|
|
4
|
+
* surfaces; the Pi comparison command withholds them and reads Pi's own profile.
|
|
8
5
|
*/
|
|
9
6
|
export type OwnedUiProfileId = LaunchProfileId;
|
|
10
7
|
export interface InteractiveRuntimeSelection {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, PROMPT_GLYPH, blockJumpTarget, dialogValueColumn, numericValues, RAIL_COLUMNS, renderDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderStatusLine, renderListRow, renderNote, dialogRowAt, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, valueColumnFor, valueMenuFrame, promptRule, caretCell, blockRowSpan, displayWidth, faint, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, isThumbRow, layoutList, moveSelection, rowKey, scrollForSelection, scrollbarGeometry, selectableIndexes, } from "../../ui/components/index.js";
|
|
1
|
+
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, PROMPT_GLYPH, blockJumpTarget, dialogValueColumn, numericValues, RAIL_COLUMNS, renderDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderStatusLine, renderListRow, renderNote, dialogRowAt, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, valueColumnFor, valueMenuFrame, promptRule, caretCell, blockRowSpan, displayWidth, faint, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, isThumbRow, layoutList, moveSelection, rowKey, scrollForSelection, scrollbarGeometry, selectableIndexes, } from "../../ui/components/index.js";
|
|
2
2
|
export const SETTINGS_APP_ID = "settings";
|
|
3
3
|
export const SETTINGS_ROUTE = "settings";
|
|
4
4
|
const SCOPE = SETTINGS_APP_ID;
|
|
@@ -29,6 +29,7 @@ SETTINGS_SHORTCUTS.declare({ key: "left", scope: DIALOG_SCOPE, description: "Cha
|
|
|
29
29
|
SETTINGS_SHORTCUTS.declare({ key: "right", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts" }, "part-change");
|
|
30
30
|
SETTINGS_SHORTCUTS.declare({ key: "up", scope: DIALOG_SCOPE, description: "Previous part", section: "Parts" }, "part-previous");
|
|
31
31
|
SETTINGS_SHORTCUTS.declare({ key: "down", scope: DIALOG_SCOPE, description: "Next part", section: "Parts" }, "part-next");
|
|
32
|
+
assertNoShortcutConflicts(SETTINGS_SHORTCUTS.assemble());
|
|
32
33
|
const KEYS = {
|
|
33
34
|
"\u001b[A": "up",
|
|
34
35
|
"\u001b[B": "down",
|
|
@@ -56,6 +57,8 @@ export class SettingsApp {
|
|
|
56
57
|
#session;
|
|
57
58
|
#selectedKey;
|
|
58
59
|
#scroll = 0;
|
|
60
|
+
/** Keyboard navigation requests visibility once; pointer scrolling then stays free. */
|
|
61
|
+
#selectionNeedsReveal = true;
|
|
59
62
|
#reveal;
|
|
60
63
|
#notice = null;
|
|
61
64
|
#filter = null;
|
|
@@ -96,9 +99,13 @@ export class SettingsApp {
|
|
|
96
99
|
this.#panelTop = this.#panelTopForFrame;
|
|
97
100
|
const bodyHeight = Math.max(0, rect.height - footer.length);
|
|
98
101
|
const selected = indexOfKey(rows, this.#selectedKey);
|
|
99
|
-
|
|
102
|
+
if (this.#selectionNeedsReveal) {
|
|
103
|
+
this.#scroll = scrollForSelection(rows, bodyHeight, this.#scroll, selected, this.#reveal);
|
|
104
|
+
this.#selectionNeedsReveal = false;
|
|
105
|
+
}
|
|
100
106
|
this.#reveal = undefined;
|
|
101
107
|
const layout = layoutList(rows, bodyHeight, this.#scroll);
|
|
108
|
+
this.#scroll = layout.scroll;
|
|
102
109
|
const contentWidth = Math.max(0, rect.width - RAIL_COLUMNS);
|
|
103
110
|
const valueColumn = this.#valueColumn(rows);
|
|
104
111
|
const geometry = scrollbarGeometry({
|
|
@@ -121,14 +128,13 @@ export class SettingsApp {
|
|
|
121
128
|
for (const index of layout.rowIndexes) {
|
|
122
129
|
const row = rows[index];
|
|
123
130
|
if (row !== undefined && row.kind === "element") {
|
|
131
|
+
const view = this.#viewRow(row.value);
|
|
124
132
|
this.#frameRows.push({
|
|
125
|
-
key:
|
|
133
|
+
key: view.key,
|
|
126
134
|
screenRow: body.length,
|
|
127
135
|
valueColumn,
|
|
128
|
-
valueWidth:
|
|
129
|
-
|
|
130
|
-
: row.value.value === null ? 0 : displayWidth(displayValue(row.value.value)),
|
|
131
|
-
stepper: isStepper(row.value),
|
|
136
|
+
valueWidth: displayWidth(view.value),
|
|
137
|
+
stepper: view.stepper !== undefined,
|
|
132
138
|
});
|
|
133
139
|
}
|
|
134
140
|
body.push(this.#renderRow(row, index === selected, contentWidth, valueColumn, theme));
|
|
@@ -189,8 +195,11 @@ export class SettingsApp {
|
|
|
189
195
|
// End lands on the very last setting, not on the head of its section.
|
|
190
196
|
const selectable = selectableIndexes(rows);
|
|
191
197
|
const target = action === "last" ? selectable.at(-1) : selectable[0];
|
|
192
|
-
if (target !== undefined)
|
|
193
|
-
this.#
|
|
198
|
+
if (target !== undefined) {
|
|
199
|
+
this.#select(rows, target);
|
|
200
|
+
if (action === "first")
|
|
201
|
+
this.#scroll = 0;
|
|
202
|
+
}
|
|
194
203
|
return { consumed: true };
|
|
195
204
|
}
|
|
196
205
|
case "previous-value":
|
|
@@ -263,6 +272,14 @@ export class SettingsApp {
|
|
|
263
272
|
}
|
|
264
273
|
return { consumed: true, render: false };
|
|
265
274
|
}
|
|
275
|
+
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
276
|
+
// The whole list pane owns wheel scrolling, including blank space beside
|
|
277
|
+
// short labels. It must not depend on finding an item under the pointer.
|
|
278
|
+
if (event.row < 1 || event.row > this.#panelTopForFrame)
|
|
279
|
+
return { consumed: false };
|
|
280
|
+
this.#scroll = Math.max(0, this.#scroll + (event.kind === "wheel-down" ? 3 : -3));
|
|
281
|
+
return { consumed: true };
|
|
282
|
+
}
|
|
266
283
|
const row = this.#frameRows.find(candidate => candidate.screenRow === event.row - 1);
|
|
267
284
|
const previousKey = this.#hoverKey;
|
|
268
285
|
const previousRegion = this.#hoverRegion;
|
|
@@ -288,10 +305,6 @@ export class SettingsApp {
|
|
|
288
305
|
}
|
|
289
306
|
return { consumed: true };
|
|
290
307
|
}
|
|
291
|
-
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
292
|
-
this.#scroll = Math.max(0, this.#scroll + (event.kind === "wheel-down" ? 3 : -3));
|
|
293
|
-
return { consumed: true };
|
|
294
|
-
}
|
|
295
308
|
const changed = previousKey !== this.#hoverKey || previousRegion !== this.#hoverRegion;
|
|
296
309
|
return { consumed: event.kind !== "motion", render: changed };
|
|
297
310
|
}
|
|
@@ -403,6 +416,17 @@ export class SettingsApp {
|
|
|
403
416
|
if (input === null)
|
|
404
417
|
return { consumed: false };
|
|
405
418
|
const key = KEYS[data];
|
|
419
|
+
if (key === "home" || key === "end") {
|
|
420
|
+
const rows = this.#rows();
|
|
421
|
+
const selectable = selectableIndexes(rows);
|
|
422
|
+
const target = key === "end" ? selectable.at(-1) : selectable[0];
|
|
423
|
+
if (target !== undefined) {
|
|
424
|
+
this.#select(rows, target);
|
|
425
|
+
if (key === "home")
|
|
426
|
+
this.#scroll = 0;
|
|
427
|
+
}
|
|
428
|
+
return { consumed: true };
|
|
429
|
+
}
|
|
406
430
|
if (key === "up" || key === "down" || key === "shift+up" || key === "shift+down") {
|
|
407
431
|
const rows = this.#rows();
|
|
408
432
|
// Nothing found means nothing to move through; the key is still swallowed
|
|
@@ -485,6 +509,7 @@ export class SettingsApp {
|
|
|
485
509
|
if (index < 0)
|
|
486
510
|
return;
|
|
487
511
|
this.#selectedKey = rowKey(rows[index]);
|
|
512
|
+
this.#selectionNeedsReveal = true;
|
|
488
513
|
this.#notice = null;
|
|
489
514
|
}
|
|
490
515
|
#rows() {
|
|
@@ -554,7 +579,6 @@ export class SettingsApp {
|
|
|
554
579
|
key: `${entry.backend}:${entry.id}`,
|
|
555
580
|
label: labelOf(entry),
|
|
556
581
|
value,
|
|
557
|
-
...(entry.origin === "default" ? { suffix: "(default)" } : {}),
|
|
558
582
|
...(typeof shown === "number" && entry.editable ? { stepper: stepperEnds(range, shown) } : {}),
|
|
559
583
|
};
|
|
560
584
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PRODUCT_TEXT } from "../../product-identity.js";
|
|
2
2
|
export function assertLaunchProfileId(value) {
|
|
3
|
-
if (value !== "a1" && value !== "pi"
|
|
3
|
+
if (value !== "a1" && value !== "pi")
|
|
4
4
|
throw new TypeError(PRODUCT_TEXT.diagnostic(`launch profile is invalid: ${String(value)}`));
|
|
5
5
|
}
|
|
6
6
|
export function assertDimensions(dimensions) {
|
|
@@ -7,9 +7,7 @@ export interface BootstrapOptions {
|
|
|
7
7
|
readonly packageRoot: string;
|
|
8
8
|
readonly launchIntent?: {
|
|
9
9
|
readonly kind: "interactive";
|
|
10
|
-
readonly
|
|
11
|
-
readonly id: LaunchProfileId;
|
|
12
|
-
};
|
|
10
|
+
readonly profileId: LaunchProfileId;
|
|
13
11
|
};
|
|
14
12
|
readonly environment?: NodeJS.ProcessEnv;
|
|
15
13
|
readonly output?: Pick<NodeJS.WriteStream, "write">;
|
|
@@ -13,7 +13,7 @@ import { consumeMaterializationProof, materializeRelease, readCertifiedReleaseMa
|
|
|
13
13
|
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
|
|
14
14
|
export async function runBootstrap(options) {
|
|
15
15
|
const environment = { ...(options.environment ?? process.env) };
|
|
16
|
-
const launchProfileId = options.launchIntent?.
|
|
16
|
+
const launchProfileId = options.launchIntent?.profileId ?? "a1";
|
|
17
17
|
assertLaunchProfileId(launchProfileId);
|
|
18
18
|
environment[PRODUCT_IDENTITY.environment.launchProfile] = launchProfileId;
|
|
19
19
|
const output = options.output ?? process.stderr;
|
|
@@ -30,8 +30,8 @@ export class ControlStore {
|
|
|
30
30
|
migrate() {
|
|
31
31
|
const versionRow = this.database.prepare("PRAGMA user_version").get();
|
|
32
32
|
const version = versionRow.user_version;
|
|
33
|
-
if (version >
|
|
34
|
-
throw new Error(`control database version ${version} is newer than supported version
|
|
33
|
+
if (version > 6)
|
|
34
|
+
throw new Error(`control database version ${version} is newer than supported version 6`);
|
|
35
35
|
if (version !== 0)
|
|
36
36
|
this.#assertCurrentControlSchema();
|
|
37
37
|
if (version === 0) {
|
|
@@ -187,7 +187,7 @@ export class ControlStore {
|
|
|
187
187
|
CREATE TABLE launch_instances (
|
|
188
188
|
id TEXT PRIMARY KEY,
|
|
189
189
|
owner_client_id TEXT NOT NULL,
|
|
190
|
-
profile_id TEXT NOT NULL CHECK (profile_id IN ('a1', 'pi'
|
|
190
|
+
profile_id TEXT NOT NULL CHECK (profile_id IN ('a1', 'pi')),
|
|
191
191
|
state TEXT NOT NULL CHECK (state IN ('requested', 'active', 'stopping', 'completed', 'interrupted')),
|
|
192
192
|
shutdown_policy TEXT NOT NULL CHECK (shutdown_policy = 'terminate-tree-on-close'),
|
|
193
193
|
guardian_identity_json TEXT NOT NULL CHECK (json_valid(guardian_identity_json)),
|
|
@@ -208,6 +208,40 @@ export class ControlStore {
|
|
|
208
208
|
CREATE INDEX idx_launch_instances_boot ON launch_instances(owner_boot_nonce, state);
|
|
209
209
|
PRAGMA user_version = 5;
|
|
210
210
|
COMMIT;
|
|
211
|
+
`);
|
|
212
|
+
}
|
|
213
|
+
if (version <= 5) {
|
|
214
|
+
this.database.exec(`
|
|
215
|
+
BEGIN IMMEDIATE;
|
|
216
|
+
ALTER TABLE launch_instances RENAME TO launch_instances_v5;
|
|
217
|
+
DROP INDEX idx_launch_instances_owner;
|
|
218
|
+
DROP INDEX idx_launch_instances_boot;
|
|
219
|
+
CREATE TABLE launch_instances (
|
|
220
|
+
id TEXT PRIMARY KEY,
|
|
221
|
+
owner_client_id TEXT NOT NULL,
|
|
222
|
+
profile_id TEXT NOT NULL CHECK (profile_id IN ('a1', 'pi')),
|
|
223
|
+
state TEXT NOT NULL CHECK (state IN ('requested', 'active', 'stopping', 'completed', 'interrupted')),
|
|
224
|
+
shutdown_policy TEXT NOT NULL CHECK (shutdown_policy = 'terminate-tree-on-close'),
|
|
225
|
+
guardian_identity_json TEXT NOT NULL CHECK (json_valid(guardian_identity_json)),
|
|
226
|
+
root_identity_json TEXT CHECK (root_identity_json IS NULL OR json_valid(root_identity_json)),
|
|
227
|
+
containment_identity_json TEXT CHECK (containment_identity_json IS NULL OR json_valid(containment_identity_json)),
|
|
228
|
+
created_at TEXT NOT NULL,
|
|
229
|
+
activated_at TEXT,
|
|
230
|
+
stopping_at TEXT,
|
|
231
|
+
completed_at TEXT,
|
|
232
|
+
outcome_json TEXT CHECK (outcome_json IS NULL OR json_valid(outcome_json)),
|
|
233
|
+
owner_boot_nonce TEXT NOT NULL,
|
|
234
|
+
CHECK ((state = 'requested' AND root_identity_json IS NULL AND containment_identity_json IS NULL AND activated_at IS NULL AND stopping_at IS NULL AND completed_at IS NULL AND outcome_json IS NULL)
|
|
235
|
+
OR (state = 'active' AND root_identity_json IS NOT NULL AND containment_identity_json IS NOT NULL AND activated_at IS NOT NULL AND stopping_at IS NULL AND completed_at IS NULL AND outcome_json IS NULL)
|
|
236
|
+
OR (state = 'stopping' AND root_identity_json IS NOT NULL AND containment_identity_json IS NOT NULL AND activated_at IS NOT NULL AND stopping_at IS NOT NULL AND completed_at IS NULL AND outcome_json IS NULL)
|
|
237
|
+
OR (state IN ('completed', 'interrupted') AND completed_at IS NOT NULL AND outcome_json IS NOT NULL))
|
|
238
|
+
);
|
|
239
|
+
INSERT INTO launch_instances SELECT * FROM launch_instances_v5 WHERE profile_id IN ('a1', 'pi');
|
|
240
|
+
DROP TABLE launch_instances_v5;
|
|
241
|
+
CREATE INDEX idx_launch_instances_owner ON launch_instances(owner_client_id, state);
|
|
242
|
+
CREATE INDEX idx_launch_instances_boot ON launch_instances(owner_boot_nonce, state);
|
|
243
|
+
PRAGMA user_version = 6;
|
|
244
|
+
COMMIT;
|
|
211
245
|
`);
|
|
212
246
|
}
|
|
213
247
|
if (version === 0) {
|