merge: reconcile published native prerequisite and current master

Preserve canonical startup ownership, scoped evidence, current Storybook IDs, and the Codex form controls while carrying Claude effort and immutable source bindings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-12 20:40:11 -05:00
commit 48ffca9438
415 files changed
+22501 -15340

No files matched your search

+9 -2
View File
@@ -1,3 +1,4 @@
import type { SlackSetupOptions, SlackManagedProvisionInput, SlackManagedResult } from "@paperclipai/shared";
import { api } from "./client";
import type {
SlackAppConfiguration,
@@ -140,7 +141,8 @@ export interface ChatEndpoint {
messagingEndpoint?: string | null;
command?: string | null;
slackApp?: SlackAppConfiguration;
slackSetupMethod?: "automatic" | "manual" | "existing";
slackSetupMethod?: "managed" | "automatic" | "manual" | "existing";
slackManagerError?: string;
slackRegistration?: SlackRegistrationState;
slackAvatar?: SlackAvatarState;
slackAccount?: SlackAccountState;
@@ -202,7 +204,7 @@ export const chatEndpointsApi = {
api.get<ChatEndpoint>(`/chat-endpoints/${endpointId}`),
create: (
companyId: string,
input: { provider: ChatProvider; assignedAgentId: string; slackApp?: SlackAppConfiguration },
input: { provider: ChatProvider; assignedAgentId: string; slackApp?: SlackAppConfiguration; slackSetupMethod?: "managed" | "automatic" | "manual" | "existing" },
) => api.post<ChatEndpoint>(`/companies/${companyId}/chat-endpoints`, input),
update: (
endpointId: string,
@@ -216,6 +218,11 @@ export const chatEndpointsApi = {
photon?: PhotonChannelConfiguration;
},
) => api.post<ChatEndpoint>(`/chat-endpoints/${endpointId}/setup`, input),
sendSlackTestMessage: (endpointId: string, input: import("@paperclipai/shared").SlackTestMessageInput) =>
api.post<import("@paperclipai/shared").SlackTestMessageResult>(`/chat-endpoints/${endpointId}/slack/test-message`, input),
slackSetupOptions: (companyId: string) => api.get<SlackSetupOptions>(`/companies/${companyId}/chat-slack/setup-options`),
authorizeSlackManager: (endpointId: string) => api.post<import("@paperclipai/shared").SlackManagerAuthorization>(`/chat-endpoints/${endpointId}/slack/managed/authorize`, {}),
provisionManagedSlack: (endpointId: string, input: SlackManagedProvisionInput) => api.post<SlackManagedResult>(`/chat-endpoints/${endpointId}/slack/managed/provision`, input),
createSlackApp: (endpointId: string, input: SlackRegistrationInput) =>
api.post<ChatEndpoint>(`/chat-endpoints/${endpointId}/slack/registration`, input),
installSlackApp: (endpointId: string) =>
+11 -9
View File
@@ -3,7 +3,7 @@ import {
createTenantSessionRecoveryCoordinator,
tenantSessionRecovery,
} from "@/lib/tenant-session-recovery";
import { __inflightGetCount, api, detachInflightGet } from "./client";
import { api, detachInflightGet } from "./client";
import { toolsApi } from "./tools";
interface Deferred<T> {
@@ -93,6 +93,10 @@ describe("tenant-session recovery", () => {
status: 401,
message: "unauthorized",
});
fetchMock.mockResolvedValue(jsonResponse({ recovered: true }));
await expect(api.get("/ordinary-401")).resolves.toEqual({ recovered: true });
expect(fetchMock).toHaveBeenCalledTimes(2);
});
});
@@ -104,13 +108,10 @@ describe("in-tab GET coalescing", () => {
const p1 = api.get("/coalesce-a");
const p2 = api.get("/coalesce-a");
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(__inflightGetCount()).toBe(1);
d.resolve(jsonResponse({ value: 1 }));
expect(await p1).toEqual({ value: 1 });
expect(await p2).toEqual({ value: 1 });
// Entry cleared once settled.
expect(__inflightGetCount()).toBe(0);
});
it("issues a fresh fetch after the previous one settles", async () => {
@@ -140,10 +141,8 @@ describe("in-tab GET coalescing", () => {
const first = deferred<Response>();
fetchMock.mockReturnValueOnce(first.promise);
const previousAccount = api.get("/detach-me");
expect(__inflightGetCount()).toBe(1);
detachInflightGet("/detach-me");
expect(__inflightGetCount()).toBe(0);
const second = deferred<Response>();
fetchMock.mockReturnValueOnce(second.promise);
@@ -155,7 +154,6 @@ describe("in-tab GET coalescing", () => {
second.resolve(jsonResponse({ companies: ["current"] }));
expect(await previousAccount).toEqual({ companies: ["previous"] });
expect(await currentAccount).toEqual({ companies: ["current"] });
expect(__inflightGetCount()).toBe(0);
});
it("never coalesces mutations", async () => {
@@ -188,7 +186,7 @@ describe("per-caller abort semantics", () => {
expect(await p2).toEqual({ value: 2 });
});
it("aborts the shared fetch once every caller has aborted", async () => {
it("aborts the shared fetch after all callers cancel and permits a fresh request", async () => {
const d = deferred<Response>();
let sharedSignal: AbortSignal | undefined;
fetchMock.mockImplementation((_url: string, init: RequestInit) => {
@@ -206,7 +204,11 @@ describe("per-caller abort semantics", () => {
await expect(p1).rejects.toMatchObject({ name: "AbortError" });
await expect(p2).rejects.toMatchObject({ name: "AbortError" });
expect(sharedSignal?.aborted).toBe(true);
expect(__inflightGetCount()).toBe(0);
fetchMock.mockResolvedValueOnce(jsonResponse({ value: "fresh" }));
const fresh = api.get("/abort-b");
expect(fetchMock).toHaveBeenCalledTimes(2);
expect(await fresh).toEqual({ value: "fresh" });
});
it("rejects immediately if the caller signal is already aborted", async () => {
-5
View File
@@ -165,11 +165,6 @@ export function detachInflightGet(path: string): void {
inflightGets.delete(path);
}
/** Test-only: number of in-flight coalesced GET keys. */
export function __inflightGetCount(): number {
return inflightGets.size;
}
function isRequestOptions(value: unknown): value is RequestOptions {
return typeof value === "object" && value !== null && "signal" in value;
}