Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
import type {
|
|
AgentHostUserProject,
|
|
AgentHostUserProjectsApi
|
|
} from "../../../host/agentHostApi";
|
|
import { areWorkspaceUserProjectPathsEqual } from "@tutti-os/workspace-user-project/core";
|
|
export {
|
|
projectAgentApprovalPromptFromInteraction as interactiveApprovalFromInteraction,
|
|
projectAgentInteractivePromptFromInteraction as interactivePromptFromInteraction
|
|
} from "../../../shared/agentConversation/projection/agentInteractionPromptProjection";
|
|
export function normalizeProjectConversationPath(
|
|
path: string | null | undefined
|
|
): string {
|
|
const normalized = path?.trim().replaceAll("\\", "/") ?? "";
|
|
if (!normalized) {
|
|
return "";
|
|
}
|
|
return normalized.replace(/\/+$/, "") || "/";
|
|
}
|
|
|
|
export function omitConversationLocalState<T>(
|
|
current: Record<string, T>,
|
|
conversationIds: ReadonlySet<string>
|
|
): Record<string, T> {
|
|
let changed = false;
|
|
const next = { ...current };
|
|
for (const conversationId of conversationIds) {
|
|
if (conversationId in next) {
|
|
delete next[conversationId];
|
|
changed = true;
|
|
}
|
|
}
|
|
return changed ? next : current;
|
|
}
|
|
|
|
export function areAgentGUIUserProjectsEqual(
|
|
left: readonly AgentHostUserProject[],
|
|
right: readonly AgentHostUserProject[]
|
|
): boolean {
|
|
return (
|
|
left.length === right.length &&
|
|
left.every((project, index) => {
|
|
const candidate = right[index];
|
|
return (
|
|
candidate !== undefined &&
|
|
project.id === candidate.id &&
|
|
areWorkspaceUserProjectPathsEqual(project.path, candidate.path) &&
|
|
project.label === candidate.label &&
|
|
project.sectionKey === candidate.sectionKey &&
|
|
project.pinnedAtUnixMs === candidate.pinnedAtUnixMs &&
|
|
project.createdAtUnixMs === candidate.createdAtUnixMs &&
|
|
project.updatedAtUnixMs === candidate.updatedAtUnixMs &&
|
|
project.lastUsedAtUnixMs === candidate.lastUsedAtUnixMs
|
|
);
|
|
})
|
|
);
|
|
}
|
|
|
|
export function upsertAgentGUIUserProject(
|
|
projects: readonly AgentHostUserProject[],
|
|
project: {
|
|
id: string;
|
|
path: string;
|
|
label: string;
|
|
sectionKey?: string;
|
|
createdAtUnixMs?: number;
|
|
updatedAtUnixMs?: number;
|
|
lastUsedAtUnixMs?: number | null;
|
|
pinnedAtUnixMs: number;
|
|
}
|
|
): AgentHostUserProject[] {
|
|
const normalizedProject: AgentHostUserProject = {
|
|
...(project.createdAtUnixMs === undefined
|
|
? {}
|
|
: { createdAtUnixMs: project.createdAtUnixMs }),
|
|
id: project.id,
|
|
...(project.lastUsedAtUnixMs === undefined ||
|
|
project.lastUsedAtUnixMs === null
|
|
? {}
|
|
: { lastUsedAtUnixMs: project.lastUsedAtUnixMs }),
|
|
label: project.label,
|
|
path: project.path,
|
|
pinnedAtUnixMs: project.pinnedAtUnixMs,
|
|
...(project.sectionKey === undefined
|
|
? {}
|
|
: { sectionKey: project.sectionKey }),
|
|
...(project.updatedAtUnixMs === undefined
|
|
? {}
|
|
: { updatedAtUnixMs: project.updatedAtUnixMs })
|
|
};
|
|
const index = projects.findIndex(
|
|
(candidate) =>
|
|
candidate.id === normalizedProject.id ||
|
|
areWorkspaceUserProjectPathsEqual(candidate.path, normalizedProject.path)
|
|
);
|
|
if (index === -1) {
|
|
return [...projects, normalizedProject];
|
|
}
|
|
const next = [...projects];
|
|
next[index] = normalizedProject;
|
|
return next;
|
|
}
|
|
|
|
export function readAgentGUIUserProjectSnapshot(
|
|
api: AgentHostUserProjectsApi | undefined
|
|
): AgentHostUserProject[] {
|
|
const projects = api?.service?.getSnapshot?.().projects ?? [];
|
|
return projects.map((project) => ({
|
|
...(project.createdAtUnixMs === undefined
|
|
? {}
|
|
: { createdAtUnixMs: project.createdAtUnixMs }),
|
|
id: project.id,
|
|
...(project.lastUsedAtUnixMs === undefined ||
|
|
project.lastUsedAtUnixMs === null
|
|
? {}
|
|
: { lastUsedAtUnixMs: project.lastUsedAtUnixMs }),
|
|
label: project.label,
|
|
path: project.path,
|
|
pinnedAtUnixMs: project.pinnedAtUnixMs,
|
|
...(project.sectionKey === undefined
|
|
? {}
|
|
: { sectionKey: project.sectionKey }),
|
|
...(project.updatedAtUnixMs === undefined
|
|
? {}
|
|
: { updatedAtUnixMs: project.updatedAtUnixMs })
|
|
}));
|
|
}
|
|
|
|
export function readAgentGUIUserProjectMutationPending(
|
|
api: AgentHostUserProjectsApi | undefined
|
|
): boolean {
|
|
return api?.service?.getSnapshot?.().isMutationPending === true;
|
|
}
|