源码快照 @ 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:
@@ -0,0 +1,304 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildAgentConversationHandoffPrompt,
|
||||
handoffProjectPathForConversation,
|
||||
isAgentGUIHomeStatusNoticeVisible,
|
||||
resolveAgentGUITuttiStopTargets,
|
||||
resolveAgentGUIInteractionDisabledReason,
|
||||
resolveAgentGUIHomeNoticeChrome,
|
||||
resolveAgentGUIStopControl,
|
||||
shouldShowAgentGUIStopButton
|
||||
} from "./agentGUIDetailModelHelpers.ts";
|
||||
|
||||
describe("buildAgentConversationHandoffPrompt", () => {
|
||||
it("delegates the active conversation to the canonical session handoff draft", () => {
|
||||
expect(
|
||||
buildAgentConversationHandoffPrompt({
|
||||
activeConversation: {
|
||||
id: "session-1",
|
||||
agentTargetId: "local:claude-code",
|
||||
provider: "claude-code",
|
||||
title: "Session 1",
|
||||
titleFallback: null,
|
||||
status: "completed",
|
||||
cwd: "/workspace/project-a",
|
||||
updatedAtUnixMs: 1
|
||||
},
|
||||
currentUserId: "user-1",
|
||||
labels: { untitledConversationTitle: "Untitled conversation" },
|
||||
selectedAgentTarget: {
|
||||
targetId: "local:claude-code",
|
||||
agentTargetId: "local:claude-code",
|
||||
label: "Claude Code",
|
||||
provider: "claude-code",
|
||||
ref: {
|
||||
kind: "agent-directory",
|
||||
provider: "claude-code",
|
||||
agentTargetId: "local:claude-code"
|
||||
}
|
||||
},
|
||||
uiLanguage: "en",
|
||||
workspaceId: "room-1"
|
||||
})
|
||||
).toBe(
|
||||
"[@Session 1](mention://agent-session/session-1?agentTargetId=local%3Aclaude-code&workspaceId=room-1) "
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldShowAgentGUIStopButton", () => {
|
||||
const idle = {
|
||||
hasPendingApproval: false,
|
||||
hasPendingInteractivePrompt: false,
|
||||
isAuthBlocked: false,
|
||||
isCancelPending: false,
|
||||
isConversationBusy: false,
|
||||
isCreatingConversation: false,
|
||||
hasPendingSubmitStopTarget: false,
|
||||
isInterrupting: false,
|
||||
isSubmitting: false,
|
||||
isUnavailable: false
|
||||
};
|
||||
|
||||
it("allows immediate stop while a new conversation is still activating", () => {
|
||||
expect(
|
||||
shouldShowAgentGUIStopButton({
|
||||
...idle,
|
||||
isCreatingConversation: true,
|
||||
isSubmitting: true
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps ordinary submission races hidden when there is no stoppable work", () => {
|
||||
expect(shouldShowAgentGUIStopButton({ ...idle, isSubmitting: true })).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
it("shows Stop when Activity Core has an exact pending-submit target", () => {
|
||||
expect(
|
||||
shouldShowAgentGUIStopButton({
|
||||
...idle,
|
||||
hasPendingSubmitStopTarget: true,
|
||||
isSubmitting: true
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps authentication and availability gates authoritative", () => {
|
||||
expect(
|
||||
shouldShowAgentGUIStopButton({
|
||||
...idle,
|
||||
isAuthBlocked: true,
|
||||
isCreatingConversation: true
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveAgentGUIInteractionDisabledReason", () => {
|
||||
it("uses the approval reason for approval prompts", () => {
|
||||
expect(
|
||||
resolveAgentGUIInteractionDisabledReason({
|
||||
promptKind: "approval",
|
||||
approvalReason: "The shared Agent owner is offline",
|
||||
interactivePromptReason: "The shared Agent caller is offline"
|
||||
})
|
||||
).toBe("The shared Agent owner is offline");
|
||||
});
|
||||
|
||||
it("uses the interactive prompt reason for non-approval prompts", () => {
|
||||
expect(
|
||||
resolveAgentGUIInteractionDisabledReason({
|
||||
promptKind: "ask-user",
|
||||
approvalReason: "The shared Agent owner is offline",
|
||||
interactivePromptReason: "The shared Agent caller is offline"
|
||||
})
|
||||
).toBe("The shared Agent caller is offline");
|
||||
});
|
||||
|
||||
it("does not expose a reason when there is no active prompt", () => {
|
||||
expect(
|
||||
resolveAgentGUIInteractionDisabledReason({
|
||||
promptKind: null,
|
||||
approvalReason: "The shared Agent owner is offline",
|
||||
interactivePromptReason: "The shared Agent caller is offline"
|
||||
})
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveAgentGUITuttiStopTargets", () => {
|
||||
it("stops only the Issue cascade when aggregate work outlives the source Turn", () => {
|
||||
expect(
|
||||
resolveAgentGUITuttiStopTargets({
|
||||
executionActive: true,
|
||||
sourceHasStoppableWork: false
|
||||
})
|
||||
).toEqual({ stopExecution: true, stopSession: false });
|
||||
});
|
||||
|
||||
it("stops both the Issue cascade and a live source Turn", () => {
|
||||
expect(
|
||||
resolveAgentGUITuttiStopTargets({
|
||||
executionActive: true,
|
||||
sourceHasStoppableWork: true
|
||||
})
|
||||
).toEqual({ stopExecution: true, stopSession: true });
|
||||
});
|
||||
|
||||
it("preserves ordinary Session stop outside Tutti execution", () => {
|
||||
expect(
|
||||
resolveAgentGUITuttiStopTargets({
|
||||
executionActive: false,
|
||||
sourceHasStoppableWork: false
|
||||
})
|
||||
).toEqual({ stopExecution: false, stopSession: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("Home status presentation", () => {
|
||||
it.each([
|
||||
"agent-sharing-revoked",
|
||||
"transport-connecting",
|
||||
"transport-unavailable"
|
||||
] as const)(
|
||||
"gives %s recovery chrome priority over other bottom-dock notices",
|
||||
(kind) => {
|
||||
expect(
|
||||
isAgentGUIHomeStatusNoticeVisible({
|
||||
kind,
|
||||
message: "Connection unavailable",
|
||||
canRetry: false
|
||||
})
|
||||
).toBe(true);
|
||||
}
|
||||
);
|
||||
|
||||
it("does not hide existing chrome while reconnecting is still delayed", () => {
|
||||
expect(isAgentGUIHomeStatusNoticeVisible(null)).toBe(false);
|
||||
expect(
|
||||
isAgentGUIHomeStatusNoticeVisible({
|
||||
kind: "failed",
|
||||
message: "Existing failure",
|
||||
canRetry: false
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it.each(["transport-connecting", "transport-unavailable"] as const)(
|
||||
"keeps the pending prompt visible for interaction-scoped %s chrome",
|
||||
(kind) => {
|
||||
expect(
|
||||
isAgentGUIHomeStatusNoticeVisible({
|
||||
kind,
|
||||
message: "Connection unavailable",
|
||||
canRetry: false,
|
||||
interactionScoped: true
|
||||
})
|
||||
).toBe(false);
|
||||
}
|
||||
);
|
||||
|
||||
it("projects target connection chrome onto the empty Home composer", () => {
|
||||
const inlineNoticeChrome = {
|
||||
auth: null,
|
||||
approval: null,
|
||||
recovery: {
|
||||
kind: "failed" as const,
|
||||
message: "Existing failure"
|
||||
},
|
||||
rawState: null
|
||||
};
|
||||
const sessionChrome = {
|
||||
auth: null,
|
||||
approval: null,
|
||||
recovery: {
|
||||
kind: "transport-connecting" as const,
|
||||
message: "Connecting to device..."
|
||||
},
|
||||
rawState: null
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveAgentGUIHomeNoticeChrome({
|
||||
inlineNoticeChrome,
|
||||
sessionChrome
|
||||
})
|
||||
).toBe(sessionChrome);
|
||||
});
|
||||
|
||||
it("keeps ordinary Home notices when target connection chrome is absent", () => {
|
||||
const inlineNoticeChrome = {
|
||||
auth: null,
|
||||
approval: null,
|
||||
recovery: {
|
||||
kind: "failed" as const,
|
||||
message: "Existing failure"
|
||||
},
|
||||
rawState: null
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveAgentGUIHomeNoticeChrome({
|
||||
inlineNoticeChrome,
|
||||
sessionChrome: {
|
||||
auth: null,
|
||||
approval: null,
|
||||
recovery: null,
|
||||
rawState: null
|
||||
}
|
||||
})
|
||||
).toBe(inlineNoticeChrome);
|
||||
});
|
||||
|
||||
it("keeps Stop actionable while submission commands are blocked", () => {
|
||||
expect(
|
||||
resolveAgentGUIStopControl({
|
||||
hasPendingApproval: false,
|
||||
hasPendingInteractivePrompt: false,
|
||||
isAuthBlocked: false,
|
||||
isCancelPending: false,
|
||||
isConversationBusy: true,
|
||||
isCreatingConversation: false,
|
||||
hasPendingSubmitStopTarget: false,
|
||||
isInterrupting: false,
|
||||
isSubmitting: false,
|
||||
isUnavailable: false
|
||||
})
|
||||
).toEqual({ disabled: false, visible: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("handoffProjectPathForConversation", () => {
|
||||
it("keeps the canonical project path for the destination session", () => {
|
||||
expect(
|
||||
handoffProjectPathForConversation({
|
||||
cwd: "/workspace/fallback",
|
||||
project: { path: " /workspace/project-a " },
|
||||
railSectionKey: "project:/workspace/project-a"
|
||||
} as never)
|
||||
).toBe("/workspace/project-a");
|
||||
});
|
||||
|
||||
it("falls back to the source cwd when project metadata is unavailable", () => {
|
||||
expect(
|
||||
handoffProjectPathForConversation({
|
||||
cwd: " /workspace/project-b ",
|
||||
project: null,
|
||||
railSectionKey: "project:/workspace/project-b"
|
||||
} as never)
|
||||
).toBe("/workspace/project-b");
|
||||
});
|
||||
|
||||
it("omits the cwd when the source belongs to conversations", () => {
|
||||
expect(
|
||||
handoffProjectPathForConversation({
|
||||
cwd: " /workspace/conversation ",
|
||||
project: { path: " /workspace/stale-project " },
|
||||
railSectionKey: " conversations "
|
||||
} as never)
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user