源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user