Files
tutti/packages/agent/gui/agent-gui/agentGuiNode/controller/agentGuiController.interactiveHelpers.ts
agent-radar 2ed3415fb7
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
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

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;
}