@timurproko/a1 0.2.7-dev.1287 → 0.2.7-dev.1290
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 +4 -0
- package/bin/cli.js +4 -0
- package/dist/cli/capabilities.d.ts +1 -0
- package/dist/cli/capabilities.js +1 -1
- package/dist/cli/dispatch.d.ts +4 -0
- package/dist/cli/dispatch.js +34 -1
- package/dist/cli/session-color.d.ts +6 -0
- package/dist/cli/session-color.js +44 -0
- package/dist/cli/session-context.js +5 -0
- package/dist/composition/owned-settings.d.ts +2 -2
- package/dist/composition/owned-settings.js +2 -2
- package/dist/composition/owned-ui.js +31 -11
- package/dist/composition/session-colors.d.ts +5 -0
- package/dist/composition/session-colors.js +33 -0
- package/dist/composition/session-runtime-registry.d.ts +3 -1
- package/dist/composition/session-runtime-registry.js +32 -3
- package/dist/contracts/owned-ui/index.d.ts +2 -2
- package/dist/contracts/owned-ui/index.js +1 -0
- package/dist/contracts/presentation/progress-palette.generated.d.ts +31 -5
- package/dist/contracts/presentation/progress-palette.generated.js +1 -1
- package/dist/features/launch/session-context.d.ts +9 -0
- package/dist/features/launch/session-context.js +7 -1
- package/dist/features/owned-ui/settings-app.js +1 -1
- package/dist/foundation/lifecycle/index.d.ts +6 -2
- package/dist/foundation/lifecycle/index.js +3 -1
- package/dist/foundation/lifecycle/session-control.d.ts +26 -0
- package/dist/foundation/lifecycle/session-control.js +222 -0
- package/dist/foundation/lifecycle/session-repository-context.d.ts +27 -0
- package/dist/foundation/lifecycle/session-repository-context.js +106 -7
- package/dist/foundation/lifecycle/session-worktree-completion.d.ts +35 -0
- package/dist/foundation/lifecycle/session-worktree-completion.js +190 -0
- package/dist/foundation/release/early-accent.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +8 -6
- package/dist/integrations/pi/engine/runtime-integration.js +1 -1
- package/dist/integrations/pi/engine/worktree-tools.d.ts +5 -2
- package/dist/integrations/pi/engine/worktree-tools.js +18 -3
- package/dist/ui/settings/declarations.d.ts +18 -2
- package/dist/ui/settings/declarations.js +14 -4
- package/dist/ui/settings/early-accent.d.ts +16 -0
- package/dist/ui/settings/early-accent.js +1 -3
- package/dist/ui/settings/manager.d.ts +4 -2
- package/dist/ui/settings/manager.js +36 -4
- package/dist/ui/settings/resolution.js +3 -2
- package/docs/architecture/project-structure.md +1 -1
- package/docs/features/session-colors.md +66 -0
- package/docs/features/worktrees.md +30 -2
- package/docs/local-worktree-cleanup.md +3 -1
- package/docs/openspec-archive-automation.md +3 -3
- package/docs/worktree-link-recovery.md +2 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -99,6 +99,10 @@ a1 pi
|
|
|
99
99
|
|
|
100
100
|
<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>
|
|
101
101
|
|
|
102
|
+
## Session colors
|
|
103
|
+
|
|
104
|
+
Settings → Appearance separates a saved **Default color** (initially blue) from **Current color**, which affects only this session. Both offer blue, green, orange, pink, purple, cyan, and grey. External applications can read and change a targeted session through the [always-JSON local color API](docs/features/session-colors.md).
|
|
105
|
+
|
|
102
106
|
## Update
|
|
103
107
|
|
|
104
108
|
Update on the channel you already use (release stays on release, develop stays on develop):
|
package/bin/cli.js
CHANGED
|
@@ -54,6 +54,10 @@ process.exitCode = await dispatchCli(process.argv.slice(2), {
|
|
|
54
54
|
const { createPiPackagesPort } = await import("../dist/integrations/pi/engine/package-integration.js");
|
|
55
55
|
return await runPackageCommand(request, { createPort: createPiPackagesPort });
|
|
56
56
|
},
|
|
57
|
+
sessionColor: async arguments_ => {
|
|
58
|
+
const { runSessionColorCommand } = await import("../dist/cli/session-color.js");
|
|
59
|
+
return await runSessionColorCommand(arguments_);
|
|
60
|
+
},
|
|
57
61
|
sessionContext: async request => {
|
|
58
62
|
const { runSessionContextCommand } = await import("../dist/cli/session-context.js");
|
|
59
63
|
return await runSessionContextCommand(request);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** The Pi comparison launch is a prerelease development instrument, not product. */
|
|
2
2
|
export interface CliCapabilities {
|
|
3
3
|
readonly developmentComparison: boolean;
|
|
4
|
+
readonly sessionColors?: boolean;
|
|
4
5
|
/** Bare `update` stays on this build's channel; absent means stable. */
|
|
5
6
|
readonly runningChannel?: "stable" | "next";
|
|
6
7
|
}
|
package/dist/cli/capabilities.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { prerelease } from "semver";
|
|
2
2
|
export function cliCapabilities(version) {
|
|
3
3
|
const development = isPrereleaseVersion(version);
|
|
4
|
-
return Object.freeze({ developmentComparison: development, runningChannel: development ? "next" : "stable" });
|
|
4
|
+
return Object.freeze({ developmentComparison: development, sessionColors: true, runningChannel: development ? "next" : "stable" });
|
|
5
5
|
}
|
|
6
6
|
export function isPrereleaseVersion(version) {
|
|
7
7
|
return (prerelease(version)?.length ?? 0) > 0;
|
package/dist/cli/dispatch.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface CliHandlers {
|
|
|
10
10
|
readonly update: (channel: UpdateChannel, target?: string) => Promise<number>;
|
|
11
11
|
readonly packages: (request: PackageCommandRequest) => Promise<number>;
|
|
12
12
|
readonly sessionContext: (request: SessionContextRequest) => Promise<number>;
|
|
13
|
+
readonly sessionColor?: (arguments_: readonly string[]) => Promise<number>;
|
|
13
14
|
/** Removes A1 from the machine; absent in hosts that cannot uninstall. */
|
|
14
15
|
readonly uninstall?: (request: {
|
|
15
16
|
readonly yes: boolean;
|
|
@@ -51,6 +52,9 @@ export type CliCommand = {
|
|
|
51
52
|
} | {
|
|
52
53
|
readonly kind: "session-context";
|
|
53
54
|
readonly request: SessionContextRequest;
|
|
55
|
+
} | {
|
|
56
|
+
readonly kind: "session-color";
|
|
57
|
+
readonly arguments: readonly string[];
|
|
54
58
|
} | {
|
|
55
59
|
readonly kind: "uninstall";
|
|
56
60
|
readonly request: {
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -23,7 +23,9 @@ export function cliUsage(capabilities) {
|
|
|
23
23
|
"worktree enter <branch> [--base <branch>]",
|
|
24
24
|
"worktree attach <path>",
|
|
25
25
|
"worktree detach",
|
|
26
|
+
"worktree complete [--change <id>] [--pr <number>]",
|
|
26
27
|
"worktree list",
|
|
28
|
+
"session color list | get [--session <id>] | set <color> [--session <id>]",
|
|
27
29
|
"session worktrees",
|
|
28
30
|
"session link-worktree <path>",
|
|
29
31
|
"session unlink-worktree",
|
|
@@ -59,8 +61,14 @@ export function cliHelp(capabilities) {
|
|
|
59
61
|
` ${command} worktree enter <branch> [--base <branch>]`,
|
|
60
62
|
` ${command} worktree attach <path>`,
|
|
61
63
|
` ${command} worktree detach`,
|
|
64
|
+
` ${command} worktree complete [--change <id>] [--pr <number>]`,
|
|
62
65
|
` ${command} worktree list`,
|
|
63
66
|
"",
|
|
67
|
+
"Session colors (always JSON; explicit session id required outside the session shell):",
|
|
68
|
+
` ${command} session color list`,
|
|
69
|
+
` ${command} session color get --session <id>`,
|
|
70
|
+
` ${command} session color set <color> --session <id>`,
|
|
71
|
+
"",
|
|
64
72
|
"Session context (compatibility aliases):",
|
|
65
73
|
` ${command} session worktrees`,
|
|
66
74
|
` ${command} session link-worktree <path>`,
|
|
@@ -97,6 +105,12 @@ export async function dispatchCli(arguments_, handlers, output, capabilities) {
|
|
|
97
105
|
return await handlers.packages(command.request);
|
|
98
106
|
if (command.kind === "session-context")
|
|
99
107
|
return await handlers.sessionContext(command.request);
|
|
108
|
+
if (command.kind === "session-color") {
|
|
109
|
+
if (handlers.sessionColor)
|
|
110
|
+
return await handlers.sessionColor(command.arguments);
|
|
111
|
+
output.stdout(`${JSON.stringify({ error: { code: "control-unavailable", message: "Session color API is unavailable in this host." } })}\n`);
|
|
112
|
+
return 1;
|
|
113
|
+
}
|
|
100
114
|
if (command.kind === "uninstall")
|
|
101
115
|
return handlers.uninstall ? await handlers.uninstall(command.request) : 2;
|
|
102
116
|
return await handlers.update(command.channel, command.target);
|
|
@@ -135,6 +149,8 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
135
149
|
return parseUpdate(rest, capabilities.runningChannel ?? "stable");
|
|
136
150
|
if (command === "worktree")
|
|
137
151
|
return parseWorktree(rest);
|
|
152
|
+
if (command === "session" && rest[0] === "color")
|
|
153
|
+
return { kind: "session-color", arguments: rest.slice(1) };
|
|
138
154
|
if (command === "session")
|
|
139
155
|
return parseSessionContext(rest);
|
|
140
156
|
if (command?.startsWith("update:"))
|
|
@@ -155,7 +171,24 @@ function parseWorktree(rest) {
|
|
|
155
171
|
if ((action === "detach" || action === "list") && value === undefined) {
|
|
156
172
|
return { kind: "session-context", request: { action: action === "detach" ? "unlink-worktree" : "worktrees" } };
|
|
157
173
|
}
|
|
158
|
-
|
|
174
|
+
if (action === "complete") {
|
|
175
|
+
const selectors = rest.slice(1);
|
|
176
|
+
let change, pr;
|
|
177
|
+
let valid = selectors.length % 2 === 0;
|
|
178
|
+
for (let index = 0; valid && index < selectors.length; index += 2) {
|
|
179
|
+
const name = selectors[index], selected = selectors[index + 1] ?? "";
|
|
180
|
+
if (name === "--change" && change === undefined && /^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(selected))
|
|
181
|
+
change = selected;
|
|
182
|
+
else if (name === "--pr" && pr === undefined && /^[1-9][0-9]{0,8}$/u.test(selected))
|
|
183
|
+
pr = Number(selected);
|
|
184
|
+
else
|
|
185
|
+
valid = false;
|
|
186
|
+
}
|
|
187
|
+
if (valid) {
|
|
188
|
+
return { kind: "session-context", request: { action: "complete-worktree", ...(change === undefined ? {} : { change }), ...(pr === undefined ? {} : { pr }) } };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic("worktree accepts enter <branch> [--base <branch>], attach <path>, detach, complete [--change <id>] [--pr <number>], or list.") };
|
|
159
192
|
}
|
|
160
193
|
function parseSessionContext(rest) {
|
|
161
194
|
const [action, value, extra] = rest;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { UI_ACCENT_COLORS } from "../contracts/owned-ui/index.js";
|
|
2
|
+
import { requestSessionControl, resolveProductPaths } from "../foundation/lifecycle/index.js";
|
|
3
|
+
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../product-identity.js";
|
|
4
|
+
const failure = (code, message) => Object.assign(new Error(message), { code });
|
|
5
|
+
export async function runSessionColorCommand(arguments_, options = {}) {
|
|
6
|
+
const stdout = options.stdout ?? (message => process.stdout.write(message));
|
|
7
|
+
const environment = options.environment ?? process.env;
|
|
8
|
+
try {
|
|
9
|
+
const [action, ...rest] = arguments_;
|
|
10
|
+
if (action === "help" || action === "--help" || action === "-h") {
|
|
11
|
+
stdout(`${PRODUCT_TEXT.commandName} session color list | get [--session <id>] | set <color> [--session <id>]\nAlways JSON; get/set target Current color only. Outside an A1 shell, --session is required.\n`);
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
if (action === "list" && rest.length === 0) {
|
|
15
|
+
stdout(`${JSON.stringify({ colors: UI_ACCENT_COLORS })}\n`);
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
if (action !== "get" && action !== "set")
|
|
19
|
+
throw failure("invalid-request", "Use session color list, get, or set <color>.");
|
|
20
|
+
const color = action === "set" ? rest.shift() : undefined;
|
|
21
|
+
if (action === "set" && !UI_ACCENT_COLORS.includes(color))
|
|
22
|
+
throw failure("invalid-color", "Choose blue, green, orange, pink, purple, cyan, or grey.");
|
|
23
|
+
if (rest.length !== 0 && (rest.length !== 2 || rest[0] !== "--session" || !rest[1]))
|
|
24
|
+
throw failure("invalid-request", "Expected only --session followed by a complete session id.");
|
|
25
|
+
const explicit = rest.length === 2;
|
|
26
|
+
const runtimeId = environment[PRODUCT_IDENTITY.environment.sessionRuntimeId];
|
|
27
|
+
const sessionId = explicit ? rest[1] : runtimeId && environment.PI_SESSION_FILE ? environment.PI_SESSION_ID : undefined;
|
|
28
|
+
if (!sessionId)
|
|
29
|
+
throw failure("session-required", "Supply --session <id> outside an exact A1 shell runtime.");
|
|
30
|
+
const result = await requestSessionControl({
|
|
31
|
+
runtimeDir: resolveProductPaths(environment).runtimeDir, sessionId,
|
|
32
|
+
...(!explicit && runtimeId ? { runtimeId } : {}),
|
|
33
|
+
payload: { action, ...(color === undefined ? {} : { color }) },
|
|
34
|
+
});
|
|
35
|
+
stdout(`${JSON.stringify(result)}\n`);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const detail = error;
|
|
40
|
+
const code = detail.code ?? "control-failed";
|
|
41
|
+
stdout(`${JSON.stringify({ error: { code, message: detail.message } })}\n`);
|
|
42
|
+
return ["invalid-request", "invalid-color", "invalid-session", "session-required"].includes(code) ? 2 : 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -15,6 +15,9 @@ export async function runSessionContextCommand(request, options = {}) {
|
|
|
15
15
|
const outcome = await updateSessionRepositoryContext({ sessionId: identity.sessionId, sessionFile: identity.sessionFile }, request, { runtimeId: identity.runtimeId, inspectProcess: options.inspectProcess ?? inspectLiveProcess });
|
|
16
16
|
if (outcome.kind === "unlinked")
|
|
17
17
|
stdout("Session worktree context cleared.\n");
|
|
18
|
+
if (outcome.kind === "completing") {
|
|
19
|
+
stdout(`Session returned to ${outcome.startupRoot}; left ${outcome.cwd} (${outcome.branch}). Repository cleanup runs when this command's shell exits and is reported with its result.\n`);
|
|
20
|
+
}
|
|
18
21
|
if (outcome.kind === "linked")
|
|
19
22
|
stdout(`Session worktree context linked: ${outcome.cwd} (${outcome.branch})\n`);
|
|
20
23
|
if (outcome.kind === "worktrees") {
|
|
@@ -57,6 +60,8 @@ function recoveryDetail(code) {
|
|
|
57
60
|
"worktree-primary-checkout": "attach a task worktree, not the primary checkout; use worktree enter to create one",
|
|
58
61
|
"worktree-git-locked": "Git has locked this worktree; retain it and ask its owner to release the lock",
|
|
59
62
|
"worktree-foreign-repository": "the selected worktree belongs to a different repository; the previous attachment was preserved",
|
|
63
|
+
"worktree-not-attached": "no task worktree is attached to this session; nothing was changed",
|
|
64
|
+
"worktree-attachment-invalid": "the attached worktree is no longer a valid Git worktree; run worktree detach to return to the startup checkout",
|
|
60
65
|
"worktree-context-changed": "the attachment changed during the operation; no ownership was overridden",
|
|
61
66
|
};
|
|
62
67
|
return code === null ? undefined : details[code];
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { AgentSettingsPort } from "../contracts/agent-engine/index.js";
|
|
2
|
-
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
2
|
+
import type { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
3
3
|
interface OwnedSettingsManagerFactoryOptions {
|
|
4
4
|
readonly profileId: string;
|
|
5
5
|
readonly agent?: AgentSettingsPort | null;
|
|
6
6
|
readonly agentProvider?: () => AgentSettingsPort | null;
|
|
7
7
|
}
|
|
8
8
|
/** Builds the profile-global settings manager shared by the Agent and slim utility compositions. */
|
|
9
|
-
export declare function createOwnedSettingsManager(options: OwnedSettingsManagerFactoryOptions): OwnedSettingsManager
|
|
9
|
+
export declare function createOwnedSettingsManager(options: OwnedSettingsManagerFactoryOptions): Promise<OwnedSettingsManager>;
|
|
10
10
|
/** Rereads the shared settings document whenever its stat changes; returns the stop. */
|
|
11
11
|
export declare function watchSharedSettings(settings: Pick<OwnedSettingsManager, "file" | "refresh">): () => void;
|
|
12
12
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { statSync } from "node:fs";
|
|
2
2
|
import { resolveLaunchProfilePaths } from "../features/launch/profile-paths.js";
|
|
3
3
|
import { PRODUCT_IDENTITY } from "../product-identity.js";
|
|
4
|
-
import { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
5
4
|
/** Builds the profile-global settings manager shared by the Agent and slim utility compositions. */
|
|
6
|
-
export function createOwnedSettingsManager(options) {
|
|
5
|
+
export async function createOwnedSettingsManager(options) {
|
|
6
|
+
const { OwnedSettingsManager } = await import("../ui/settings/manager.js");
|
|
7
7
|
const profilePaths = resolveLaunchProfilePaths();
|
|
8
8
|
return new OwnedSettingsManager({
|
|
9
9
|
profileDir: profilePaths.agentProfile,
|
|
@@ -39,7 +39,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
39
39
|
let backend;
|
|
40
40
|
const settings = options.profileId === undefined
|
|
41
41
|
? null
|
|
42
|
-
: createOwnedSettingsManager({
|
|
42
|
+
: await createOwnedSettingsManager({
|
|
43
43
|
profileId: options.profileId,
|
|
44
44
|
agentProvider: () => backend.settingsPort(),
|
|
45
45
|
});
|
|
@@ -72,18 +72,12 @@ export async function composeOwnedUi(options = {}) {
|
|
|
72
72
|
...(options.packageVersion === undefined ? {} : { packageVersion: options.packageVersion }),
|
|
73
73
|
...(options.profileId === undefined ? {} : { profileId: options.profileId }),
|
|
74
74
|
});
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
: bareSettings.onChange(current => {
|
|
78
|
-
const accent = current.value("accentColor");
|
|
79
|
-
host.setAccentColor(accent);
|
|
80
|
-
});
|
|
81
|
-
// Rationale: separate A1 processes share one settings document; a live scope change saved in
|
|
82
|
-
// one reaches the others only by rereading that document.
|
|
75
|
+
const sessionColor = bindSessionColor(backend, bareSettings, color => host.setAccentColor(color), productPaths.runtimeDir);
|
|
76
|
+
// Rationale: peer refresh shares persisted preferences, never session-local Current color.
|
|
83
77
|
const unwatchSharedSettings = bareSettings === null
|
|
84
78
|
? () => { }
|
|
85
79
|
: watchSharedSettings(bareSettings);
|
|
86
|
-
const unsubscribeAccent = () => { unwatchSharedSettings();
|
|
80
|
+
const unsubscribeAccent = async () => { unwatchSharedSettings(); await sessionColor.dispose(); };
|
|
87
81
|
// Invariant: the Settings search and agent prompt borrow the same resolved Pi keybindings.
|
|
88
82
|
const keybindingsHost = createPiKeybindingsHost({ profile: bare ? "a1" : "pi", agentDir: backend.identity.agentDir });
|
|
89
83
|
// Rationale: Routes open only after shell construction.
|
|
@@ -118,7 +112,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
118
112
|
const releaseShared = async () => {
|
|
119
113
|
naming.dispose();
|
|
120
114
|
clipboardServices?.dispose();
|
|
121
|
-
unsubscribeAccent();
|
|
115
|
+
await unsubscribeAccent();
|
|
122
116
|
await sessionRuntimes.dispose();
|
|
123
117
|
await releaseNote.releaseClaim();
|
|
124
118
|
suggestionDiagnostics?.dispose();
|
|
@@ -184,6 +178,7 @@ export async function composeOwnedUi(options = {}) {
|
|
|
184
178
|
exitNotice = import("../app/session-shell/exit-notice.js")
|
|
185
179
|
.then(module => module.armExitNotice(backend, exitNoticePath), () => null);
|
|
186
180
|
presenter.start();
|
|
181
|
+
sessionColor.start();
|
|
187
182
|
releaseUpdates.start();
|
|
188
183
|
},
|
|
189
184
|
flush: () => backend.session.flushEvents(),
|
|
@@ -204,6 +199,31 @@ export async function composeOwnedUi(options = {}) {
|
|
|
204
199
|
};
|
|
205
200
|
return { application, settings };
|
|
206
201
|
}
|
|
202
|
+
function bindSessionColor(backend, settings, apply, runtimeDir) {
|
|
203
|
+
if (settings === null)
|
|
204
|
+
return { start() { }, async dispose() { } };
|
|
205
|
+
let control = Promise.resolve(null);
|
|
206
|
+
let started = false, stopped = false;
|
|
207
|
+
const unsubscribe = settings.onChange(current => apply(current.value("accentColor")));
|
|
208
|
+
let binding = backend.identity.sessionBindingGeneration;
|
|
209
|
+
const unbind = backend.session.onEvent(() => {
|
|
210
|
+
if (binding === backend.identity.sessionBindingGeneration)
|
|
211
|
+
return;
|
|
212
|
+
binding = backend.identity.sessionBindingGeneration;
|
|
213
|
+
settings.startSession();
|
|
214
|
+
});
|
|
215
|
+
return {
|
|
216
|
+
start() {
|
|
217
|
+
if (started || stopped)
|
|
218
|
+
return;
|
|
219
|
+
started = true;
|
|
220
|
+
control = import("./session-colors.js").then(module => stopped ? null
|
|
221
|
+
: module.startSessionColorControl(backend, settings, runtimeDir, process.env[PRODUCT_IDENTITY.environment.sessionRuntimeId]))
|
|
222
|
+
.catch(() => null);
|
|
223
|
+
},
|
|
224
|
+
async dispose() { stopped = true; unbind(); unsubscribe(); await (await control)?.dispose(); },
|
|
225
|
+
};
|
|
226
|
+
}
|
|
207
227
|
function spinnerPresenterOptions(settings) {
|
|
208
228
|
return settings === null ? {} : { spinner: {
|
|
209
229
|
snapshot: () => settings.value("spinnerStyle"),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type OwnedUiSessionBackend } from "../contracts/owned-ui/index.js";
|
|
2
|
+
import type { OwnedSettingsManager } from "../ui/settings/manager.js";
|
|
3
|
+
export declare function startSessionColorControl(backend: OwnedUiSessionBackend, settings: OwnedSettingsManager, runtimeDir: string, runtimeId?: string): Promise<{
|
|
4
|
+
dispose: () => Promise<void>;
|
|
5
|
+
}>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { UI_ACCENT_COLORS } from "../contracts/owned-ui/index.js";
|
|
3
|
+
import { serveSessionControl } from "../foundation/lifecycle/session-control.js";
|
|
4
|
+
export async function startSessionColorControl(backend, settings, runtimeDir, runtimeId = randomUUID()) {
|
|
5
|
+
const identity = () => ({ sessionId: backend.identity.currentHistorySessionId() ?? backend.identity.sessionId, binding: backend.identity.sessionBindingGeneration });
|
|
6
|
+
const control = await serveSessionControl({ runtimeDir, runtimeId, identity, handle: async (payload) => {
|
|
7
|
+
if (backend.identity.disposed)
|
|
8
|
+
throw Object.assign(new Error("The session is stopped."), { code: "session-unavailable" });
|
|
9
|
+
if (!payload || typeof payload !== "object")
|
|
10
|
+
throw Object.assign(new Error("Invalid color request."), { code: "invalid-request" });
|
|
11
|
+
const request = payload;
|
|
12
|
+
const sessionId = identity().sessionId;
|
|
13
|
+
if (request.action === "set") {
|
|
14
|
+
if (!UI_ACCENT_COLORS.includes(request.color))
|
|
15
|
+
throw Object.assign(new Error("Unknown color."), { code: "invalid-color" });
|
|
16
|
+
const result = await settings.change("a1", "accentColor", request.color);
|
|
17
|
+
if (!result.applied)
|
|
18
|
+
throw Object.assign(new Error(result.failure ?? "Color could not be applied."), { code: "control-failed" });
|
|
19
|
+
return { sessionId, color: result.effectiveValue };
|
|
20
|
+
}
|
|
21
|
+
if (request.action !== "get")
|
|
22
|
+
throw Object.assign(new Error("Unknown color action."), { code: "invalid-request" });
|
|
23
|
+
return { sessionId, color: settings.value("accentColor") };
|
|
24
|
+
} });
|
|
25
|
+
let stopped = false, binding = backend.identity.sessionBindingGeneration, publication = Promise.resolve();
|
|
26
|
+
const unsubscribe = backend.session.onEvent(() => {
|
|
27
|
+
if (stopped || binding === backend.identity.sessionBindingGeneration)
|
|
28
|
+
return;
|
|
29
|
+
binding = backend.identity.sessionBindingGeneration;
|
|
30
|
+
publication = publication.then(() => control.publish()).catch(() => { });
|
|
31
|
+
});
|
|
32
|
+
return { dispose: async () => { stopped = true; unsubscribe(); await publication; await control.dispose(); } };
|
|
33
|
+
}
|
|
@@ -17,7 +17,9 @@ export declare class SessionRuntimeRegistry {
|
|
|
17
17
|
revision: string;
|
|
18
18
|
} | null>;
|
|
19
19
|
/** Strict tool cwd lookup: transient startup failure never redirects a write to primary. */
|
|
20
|
-
toolReaderFor(agentId: string | undefined): (sessionId: string, sessionFile: string, signal: AbortSignal) => Promise<string
|
|
20
|
+
toolReaderFor(agentId: string | undefined): ((sessionId: string, sessionFile: string, signal: AbortSignal) => Promise<string>) & {
|
|
21
|
+
settleShell: (sessionId: string, sessionFile: string, signal: AbortSignal) => Promise<string | null>;
|
|
22
|
+
};
|
|
21
23
|
/** Drain publication before releasing claims; never republish after disposal. */
|
|
22
24
|
dispose(): Promise<void>;
|
|
23
25
|
}
|
|
@@ -3,6 +3,8 @@ export class SessionRuntimeRegistry {
|
|
|
3
3
|
#options;
|
|
4
4
|
#identities = new Map();
|
|
5
5
|
#activated = new Map();
|
|
6
|
+
// Invariant: a released invalid attachment is reported by the agent's next tool call instead of running elsewhere.
|
|
7
|
+
#released = new Map();
|
|
6
8
|
#abort = new AbortController();
|
|
7
9
|
#owner = null;
|
|
8
10
|
#timer = null;
|
|
@@ -26,7 +28,7 @@ export class SessionRuntimeRegistry {
|
|
|
26
28
|
const owner = await this.#ownerIdentity();
|
|
27
29
|
if (owner === null || !this.#current(agentId, identity))
|
|
28
30
|
return null;
|
|
29
|
-
const { activateSessionRepositoryContext, readActiveSessionRepositoryContext } = await import("../foundation/lifecycle/session-repository-context.js");
|
|
31
|
+
const { activateSessionRepositoryContext, readActiveSessionRepositoryContext, releaseInvalidSessionRepositoryContext } = await import("../foundation/lifecycle/session-repository-context.js");
|
|
30
32
|
if (!this.#current(agentId, identity))
|
|
31
33
|
return null;
|
|
32
34
|
const options = {
|
|
@@ -51,6 +53,14 @@ export class SessionRuntimeRegistry {
|
|
|
51
53
|
}
|
|
52
54
|
catch (error) {
|
|
53
55
|
const code = error instanceof Error && "code" in error ? error.code : null;
|
|
56
|
+
if (code === "worktree-attachment-invalid") {
|
|
57
|
+
const released = await releaseInvalidSessionRepositoryContext(identity, options);
|
|
58
|
+
if (released !== null && this.#current(agentId, identity)) {
|
|
59
|
+
this.#released.set(agentId, { identity, message: `attached worktree ${released.worktreeRoot} is no longer a valid Git worktree; `
|
|
60
|
+
+ `this session was detached and now uses ${released.startupRoot}. Nothing was deleted and this call did not run; retry it from that directory.` });
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
54
64
|
if ((code === "session-runtime-unavailable" || code === "worktree-context-changed") && this.#current(agentId, identity)) {
|
|
55
65
|
this.#activated.delete(agentId);
|
|
56
66
|
}
|
|
@@ -62,7 +72,18 @@ export class SessionRuntimeRegistry {
|
|
|
62
72
|
/** Strict tool cwd lookup: transient startup failure never redirects a write to primary. */
|
|
63
73
|
toolReaderFor(agentId) {
|
|
64
74
|
const read = this.readerFor(agentId);
|
|
65
|
-
|
|
75
|
+
/** Run a completion the just-finished shell requested, from this stable process rather than that shell. */
|
|
76
|
+
const settleShell = async (sessionId, sessionFile, signal) => {
|
|
77
|
+
const { runtimeId, inspectProcess } = this.#options;
|
|
78
|
+
if (this.#disposed || runtimeId === undefined || inspectProcess === undefined)
|
|
79
|
+
return null;
|
|
80
|
+
const { describeWorktreeCompletion, settleSessionWorktreeCompletion } = await import("../foundation/lifecycle/session-worktree-completion.js");
|
|
81
|
+
const result = await settleSessionWorktreeCompletion({ sessionId, sessionFile }, {
|
|
82
|
+
runtimeId, inspectProcess, signal, ...(agentId === undefined ? {} : { agentId }),
|
|
83
|
+
});
|
|
84
|
+
return result === null ? null : describeWorktreeCompletion(result);
|
|
85
|
+
};
|
|
86
|
+
return Object.assign(async (sessionId, sessionFile, signal) => {
|
|
66
87
|
const { retrySessionCoordination } = await import("../foundation/lifecycle/session-context-retry.js");
|
|
67
88
|
return await retrySessionCoordination(async () => {
|
|
68
89
|
signal.throwIfAborted();
|
|
@@ -75,12 +96,20 @@ export class SessionRuntimeRegistry {
|
|
|
75
96
|
if (active?.sessionId !== sessionId || active.sessionFile !== sessionFile) {
|
|
76
97
|
throw Object.assign(new Error("worktree runtime registration is still recovering"), { code: "session-runtime-unavailable" });
|
|
77
98
|
}
|
|
99
|
+
const released = this.#released.get(agentId);
|
|
100
|
+
if (released !== undefined) {
|
|
101
|
+
this.#released.delete(agentId);
|
|
102
|
+
// Invariant: work addressed to the lost checkout fails once; it is never silently applied to the startup checkout.
|
|
103
|
+
if (released.identity.sessionId === sessionId && released.identity.sessionFile === sessionFile) {
|
|
104
|
+
throw Object.assign(new Error(released.message), { code: "worktree-attachment-invalid" });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
78
107
|
if (context !== null)
|
|
79
108
|
return context.cwd;
|
|
80
109
|
const { readSessionStartupRoot } = await import("../foundation/lifecycle/session-repository-context.js");
|
|
81
110
|
return await readSessionStartupRoot({ sessionId, sessionFile });
|
|
82
111
|
}, 8_000, signal);
|
|
83
|
-
};
|
|
112
|
+
}, { settleShell });
|
|
84
113
|
}
|
|
85
114
|
/** Drain publication before releasing claims; never republish after disposal. */
|
|
86
115
|
async dispose() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { OwnedUiSessionNameState, OwnedUiSessionNameCompletion, OwnedUiSessionNamingPort } from "./session-naming.js";
|
|
2
|
-
|
|
3
|
-
export type UiAccentColor =
|
|
2
|
+
export declare const UI_ACCENT_COLORS: readonly ["blue", "green", "orange", "pink", "purple", "cyan", "grey"];
|
|
3
|
+
export type UiAccentColor = typeof UI_ACCENT_COLORS[number];
|
|
4
4
|
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";
|
|
5
5
|
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";
|
|
6
6
|
export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const UI_ACCENT_COLORS = Object.freeze(["blue", "green", "orange", "pink", "purple", "cyan", "grey"]);
|
|
1
2
|
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
3
|
export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
|
|
3
4
|
export { OWNED_UI_HIDDEN_COMMAND_NAMES, OWNED_UI_MODELS_COMMAND_NAME, OWNED_UI_WORKFLOW_COMMAND_NAMES, } from "./session-workflows.js";
|
|
@@ -29,7 +29,7 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
|
|
|
29
29
|
};
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
-
|
|
32
|
+
green: {
|
|
33
33
|
dark: {
|
|
34
34
|
truecolor: {
|
|
35
35
|
accent: string;
|
|
@@ -55,7 +55,7 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
|
|
|
55
55
|
};
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
|
-
|
|
58
|
+
orange: {
|
|
59
59
|
dark: {
|
|
60
60
|
truecolor: {
|
|
61
61
|
accent: string;
|
|
@@ -81,7 +81,7 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
|
|
|
81
81
|
};
|
|
82
82
|
};
|
|
83
83
|
};
|
|
84
|
-
|
|
84
|
+
pink: {
|
|
85
85
|
dark: {
|
|
86
86
|
truecolor: {
|
|
87
87
|
accent: string;
|
|
@@ -107,7 +107,7 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
|
|
|
107
107
|
};
|
|
108
108
|
};
|
|
109
109
|
};
|
|
110
|
-
|
|
110
|
+
purple: {
|
|
111
111
|
dark: {
|
|
112
112
|
truecolor: {
|
|
113
113
|
accent: string;
|
|
@@ -133,7 +133,33 @@ export declare const SHARED_PROGRESS_PALETTE: Readonly<{
|
|
|
133
133
|
};
|
|
134
134
|
};
|
|
135
135
|
};
|
|
136
|
-
|
|
136
|
+
cyan: {
|
|
137
|
+
dark: {
|
|
138
|
+
truecolor: {
|
|
139
|
+
accent: string;
|
|
140
|
+
border: string;
|
|
141
|
+
selectedBg: string;
|
|
142
|
+
};
|
|
143
|
+
"256color": {
|
|
144
|
+
accent: string;
|
|
145
|
+
border: string;
|
|
146
|
+
selectedBg: string;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
light: {
|
|
150
|
+
truecolor: {
|
|
151
|
+
accent: string;
|
|
152
|
+
border: string;
|
|
153
|
+
selectedBg: string;
|
|
154
|
+
};
|
|
155
|
+
"256color": {
|
|
156
|
+
accent: string;
|
|
157
|
+
border: string;
|
|
158
|
+
selectedBg: string;
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
grey: {
|
|
137
163
|
dark: {
|
|
138
164
|
truecolor: {
|
|
139
165
|
accent: string;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Generated by scripts/pi/sync-progress-palette.ts from A1's named accent projection
|
|
3
3
|
* over pinned Pi 1.5.2 (MIT), commit b4afdddf44e059c67ccf5097e5317d913521b470. Do not edit directly.
|
|
4
4
|
*/
|
|
5
|
-
export const SHARED_PROGRESS_PALETTE = Object.freeze({ "blue": { "dark": { "truecolor": { "accent": "\u001b[38;2;130;160;241m", "border": "\u001b[38;2;116;102;197m", "selectedBg": "\u001b[48;2;52;57;69m" }, "256color": { "accent": "\u001b[38;5;111m", "border": "\u001b[38;5;98m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;63;96;226m", "border": "\u001b[38;2;83;67;154m", "selectedBg": "\u001b[48;2;243;244;246m" }, "256color": { "accent": "\u001b[38;5;62m", "border": "\u001b[38;5;60m", "selectedBg": "\u001b[48;5;255m" } } }, "
|
|
5
|
+
export const SHARED_PROGRESS_PALETTE = Object.freeze({ "blue": { "dark": { "truecolor": { "accent": "\u001b[38;2;130;160;241m", "border": "\u001b[38;2;116;102;197m", "selectedBg": "\u001b[48;2;52;57;69m" }, "256color": { "accent": "\u001b[38;5;111m", "border": "\u001b[38;5;98m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;63;96;226m", "border": "\u001b[38;2;83;67;154m", "selectedBg": "\u001b[48;2;243;244;246m" }, "256color": { "accent": "\u001b[38;5;62m", "border": "\u001b[38;5;60m", "selectedBg": "\u001b[48;5;255m" } } }, "green": { "dark": { "truecolor": { "accent": "\u001b[38;2;104;183;141m", "border": "\u001b[38;2;75;132;120m", "selectedBg": "\u001b[48;2;50;60;54m" }, "256color": { "accent": "\u001b[38;5;72m", "border": "\u001b[38;5;66m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;51;126;88m", "border": "\u001b[38;2;41;93;82m", "selectedBg": "\u001b[48;2;242;244;243m" }, "256color": { "accent": "\u001b[38;5;65m", "border": "\u001b[38;5;23m", "selectedBg": "\u001b[48;5;255m" } } }, "orange": { "dark": { "truecolor": { "accent": "\u001b[38;2;231;135;83m", "border": "\u001b[38;2;178;89;79m", "selectedBg": "\u001b[48;2;67;54;48m" }, "256color": { "accent": "\u001b[38;5;173m", "border": "\u001b[38;5;131m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;174;80;16m", "border": "\u001b[38;2;133;57;49m", "selectedBg": "\u001b[48;2;245;243;242m" }, "256color": { "accent": "\u001b[38;5;130m", "border": "\u001b[38;5;95m", "selectedBg": "\u001b[48;5;255m" } } }, "pink": { "dark": { "truecolor": { "accent": "\u001b[38;2;223;122;199m", "border": "\u001b[38;2;150;91;171m", "selectedBg": "\u001b[48;2;65;53;62m" }, "256color": { "accent": "\u001b[38;5;176m", "border": "\u001b[38;5;97m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;178;56;153m", "border": "\u001b[38;2;114;61;131m", "selectedBg": "\u001b[48;2;245;243;245m" }, "256color": { "accent": "\u001b[38;5;132m", "border": "\u001b[38;5;60m", "selectedBg": "\u001b[48;5;255m" } } }, "purple": { "dark": { "truecolor": { "accent": "\u001b[38;2;167;152;215m", "border": "\u001b[38;2;105;115;167m", "selectedBg": "\u001b[48;2;58;56;66m" }, "256color": { "accent": "\u001b[38;5;140m", "border": "\u001b[38;5;61m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;116;89;180m", "border": "\u001b[38;2;68;77;130m", "selectedBg": "\u001b[48;2;243;243;245m" }, "256color": { "accent": "\u001b[38;5;97m", "border": "\u001b[38;5;60m", "selectedBg": "\u001b[48;5;255m" } } }, "cyan": { "dark": { "truecolor": { "accent": "\u001b[38;2;93;179;186m", "border": "\u001b[38;2;74;128;146m", "selectedBg": "\u001b[48;2;48;60;61m" }, "256color": { "accent": "\u001b[38;5;73m", "border": "\u001b[38;5;66m", "selectedBg": "\u001b[48;5;59m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;40;122;129m", "border": "\u001b[38;2;40;89;106m", "selectedBg": "\u001b[48;2;241;244;244m" }, "256color": { "accent": "\u001b[38;5;30m", "border": "\u001b[38;5;23m", "selectedBg": "\u001b[48;5;255m" } } }, "grey": { "dark": { "truecolor": { "accent": "\u001b[38;2;163;163;163m", "border": "\u001b[38;2;119;119;119m", "selectedBg": "\u001b[48;2;57;57;57m" }, "256color": { "accent": "\u001b[38;5;247m", "border": "\u001b[38;5;243m", "selectedBg": "\u001b[48;5;237m" } }, "light": { "truecolor": { "accent": "\u001b[38;2;111;111;111m", "border": "\u001b[38;2;84;84;84m", "selectedBg": "\u001b[48;2;244;244;244m" }, "256color": { "accent": "\u001b[38;5;242m", "border": "\u001b[38;5;240m", "selectedBg": "\u001b[48;5;255m" } } } });
|
|
6
6
|
export const SHARED_PROGRESS_ACCENT_ANSI = SHARED_PROGRESS_PALETTE.blue.dark.truecolor.accent;
|
|
@@ -9,6 +9,10 @@ export type SessionContextRequest = {
|
|
|
9
9
|
readonly base?: string;
|
|
10
10
|
} | {
|
|
11
11
|
readonly action: "unlink-worktree";
|
|
12
|
+
} | {
|
|
13
|
+
readonly action: "complete-worktree";
|
|
14
|
+
readonly change?: string;
|
|
15
|
+
readonly pr?: number;
|
|
12
16
|
} | {
|
|
13
17
|
readonly action: "worktrees";
|
|
14
18
|
};
|
|
@@ -18,6 +22,11 @@ export type SessionContextOutcome = {
|
|
|
18
22
|
readonly branch: string;
|
|
19
23
|
} | {
|
|
20
24
|
readonly kind: "unlinked";
|
|
25
|
+
} | {
|
|
26
|
+
readonly kind: "completing";
|
|
27
|
+
readonly cwd: string;
|
|
28
|
+
readonly branch: string;
|
|
29
|
+
readonly startupRoot: string;
|
|
21
30
|
} | {
|
|
22
31
|
readonly kind: "worktrees";
|
|
23
32
|
readonly entries: readonly SessionWorktreeInventoryEntry[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { clearSessionRepositoryContext, enterSessionRepositoryWorktree, listSessionRepositoryWorktrees, retrySessionCoordination, setSessionRepositoryContext, } from "../../foundation/lifecycle/index.js";
|
|
1
|
+
import { clearSessionRepositoryContext, enterSessionRepositoryWorktree, listSessionRepositoryWorktrees, requestSessionWorktreeCompletion, retrySessionCoordination, setSessionRepositoryContext, } from "../../foundation/lifecycle/index.js";
|
|
2
2
|
export { PRIMARY_SESSION_AGENT_ID } from "../../foundation/lifecycle/index.js";
|
|
3
3
|
export async function updateSessionRepositoryContext(identity, request, runtime) {
|
|
4
4
|
const options = {
|
|
@@ -14,6 +14,12 @@ export async function updateSessionRepositoryContext(identity, request, runtime)
|
|
|
14
14
|
await clearSessionRepositoryContext(identity, options);
|
|
15
15
|
return { kind: "unlinked" };
|
|
16
16
|
}
|
|
17
|
+
if (request.action === "complete-worktree") {
|
|
18
|
+
return { kind: "completing", ...await requestSessionWorktreeCompletion(identity, {
|
|
19
|
+
...(request.change === undefined ? {} : { change: request.change }),
|
|
20
|
+
...(request.pr === undefined ? {} : { pr: request.pr }),
|
|
21
|
+
}, options) };
|
|
22
|
+
}
|
|
17
23
|
if (request.action === "worktrees") {
|
|
18
24
|
return { kind: "worktrees", entries: await listSessionRepositoryWorktrees(identity, options) };
|
|
19
25
|
}
|
|
@@ -732,7 +732,7 @@ export class SettingsApp {
|
|
|
732
732
|
const state = {
|
|
733
733
|
choices: menu.choices.map(choice => displaySettingValue(menu.entry, choice)),
|
|
734
734
|
...(menu.preview !== null ? { previews: menu.preview.frames(menu.choices, menu.index, theme) }
|
|
735
|
-
: menu.entry.id
|
|
735
|
+
: ["accentColor", "defaultAccentColor"].includes(menu.entry.id) ? {
|
|
736
736
|
previews: menu.choices.map(choice => theme.accentPreview?.(String(choice), "■") ?? ""),
|
|
737
737
|
} : {}),
|
|
738
738
|
current: this.#edits.shown(menu.entry) === null ? null : displaySettingValue(menu.entry, this.#edits.shown(menu.entry)),
|