mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 05:16:50 +01:00
Merge current master and regenerate the delegated token migration
Preserve the upstream environment-skill runtime migration and regenerate the gateway responsible-user column as migration 0379. Keep the additive column idempotent. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
db3190fe13
247 files changed
+14906
-803
No files matched your search
@@ -8,3 +8,12 @@ export function isHeartbeatRunVisibleInMine(
|
||||
// Preserve unattributed historical runs for the single-user local board.
|
||||
return currentUserId === "local-board";
|
||||
}
|
||||
|
||||
/** The inbox lists failures only when the agent's latest observed run failed. */
|
||||
export function latestFailedRunsByAgent<T extends { agentId: string; status: string; createdAt: Date | string }>(runs: readonly T[]): T[] {
|
||||
const latest = new Map<string, T>();
|
||||
for (const run of [...runs].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())) {
|
||||
if (!latest.has(run.agentId)) latest.set(run.agentId, run);
|
||||
}
|
||||
return [...latest.values()].filter((run) => run.status === "failed" || run.status === "timed_out");
|
||||
}
|
||||
@@ -2796,7 +2796,7 @@ export { restoreAgentInstructionSchema } from "./validators/agent.js";
|
||||
export type { AgentInstructionCandidate } from "./types/agent.js";
|
||||
export { resolveAgentInstructionCandidateSchema, type ResolveAgentInstructionCandidate } from "./validators/agent.js";
|
||||
|
||||
export { isHeartbeatRunVisibleInMine } from "./heartbeat-inbox.js";
|
||||
export { isHeartbeatRunVisibleInMine, latestFailedRunsByAgent } from "./heartbeat-inbox.js";
|
||||
export * from "./browser-use.js";
|
||||
|
||||
export * from "./types/skill-source.js";
|
||||
|
||||
@@ -843,6 +843,8 @@ export type IssueSummary = Pick<
|
||||
};
|
||||
|
||||
export interface Issue {
|
||||
/** Collection projections omit task bodies and cannot seed the detail cache. */
|
||||
listProjection?: "index" | "rows";
|
||||
statusVersion?: number;
|
||||
/** True only while the title is the provisional slice of the initial prompt. */
|
||||
titleNeedsGeneration?: boolean;
|
||||
@@ -958,6 +960,7 @@ export interface Issue {
|
||||
|
||||
export type CompactIssue = Pick<
|
||||
Issue,
|
||||
| "listProjection"
|
||||
| "externalConversationState"
|
||||
| "id"
|
||||
| "companyId"
|
||||
|
||||
@@ -191,6 +191,8 @@ export interface SandboxProviderCapabilities {
|
||||
}
|
||||
|
||||
export interface PluginEnvironmentDriverDeclaration {
|
||||
/** Plugin-managed skill keys automatically included when this environment is selected. */
|
||||
skillKeys?: string[];
|
||||
/** Provides Runner execution, resource preparation, and PRP connections via environmentTask. */
|
||||
supportsTasks?: boolean;
|
||||
freshWorkspaceVersion?: 1;
|
||||
|
||||
@@ -3,4 +3,6 @@ export interface SidebarBadges {
|
||||
approvals: number;
|
||||
failedRuns: number;
|
||||
joinRequests: number;
|
||||
/** Visible unread Mine tasks, retained so optimistic archive can adjust the badge. */
|
||||
unreadIssueIds?: string[];
|
||||
}
|
||||
@@ -33,6 +33,17 @@ describe("plugin capability constants", () => {
|
||||
});
|
||||
|
||||
describe("plugin manifest validators", () => {
|
||||
it("limits environment skills to unique declarations owned by the plugin", () => {
|
||||
const manifest = { ...buildSandboxProviderManifest({ skillKeys: ["desktop"] }),
|
||||
capabilities: ["environment.drivers.register", "skills.managed"],
|
||||
skills: [{ skillKey: "desktop", displayName: "Desktop" }] };
|
||||
expect(pluginManifestV1Schema.parse(manifest).environmentDrivers![0].skillKeys).toEqual(["desktop"]);
|
||||
for (const keys of [["missing"], ["desktop", "desktop"]]) {
|
||||
expect(pluginManifestV1Schema.safeParse({ ...manifest,
|
||||
environmentDrivers: [{ ...manifest.environmentDrivers[0], skillKeys: keys }] }).success).toBe(false);
|
||||
}
|
||||
expect(pluginManifestV1Schema.safeParse({ ...manifest, capabilities: ["environment.drivers.register"] }).success).toBe(false);
|
||||
});
|
||||
it("requires authority for required agent lifecycle participants", () => {
|
||||
const manifest = { id: "example.lifecycle", apiVersion: 1, version: "0.1.0", displayName: "Lifecycle", description: "Lifecycle tests", author: "Tests", categories: ["automation"], entrypoints: { worker: "worker.js" }, agentLifecycle: true };
|
||||
expect(pluginManifestV1Schema.safeParse({ ...manifest, capabilities: ["agents.read"] }).success).toBe(false);
|
||||
|
||||
@@ -177,6 +177,7 @@ export type SandboxProviderCapabilitiesInput = z.infer<typeof sandboxProviderCap
|
||||
// validation error, not a silently dropped field. A misspelled capability name
|
||||
// (for example `supportsLoginPTY`) fails validation instead of dropping.
|
||||
export const pluginEnvironmentDriverDeclarationSchema = z.object({
|
||||
skillKeys: z.array(z.string().min(1).max(100)).max(100).optional(),
|
||||
supportsTasks: z.boolean().optional(),
|
||||
freshWorkspaceVersion: z.literal(1).optional(),
|
||||
warmTaskVersion: z.literal(1).optional(),
|
||||
@@ -898,6 +899,13 @@ export const pluginManifestV1Schema = z.object({
|
||||
}
|
||||
}
|
||||
|
||||
for (const [index, driver] of (manifest.environmentDrivers ?? []).entries()) {
|
||||
const keys = driver.skillKeys ?? [];
|
||||
if (new Set(keys).size !== keys.length || keys.some(key => !manifest.skills?.some(skill => skill.skillKey === key))) {
|
||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Environment skill keys must be unique references to this plugin's managed skills", path: ["environmentDrivers", index, "skillKeys"] });
|
||||
}
|
||||
}
|
||||
|
||||
if (manifest.agents && manifest.agents.length > 0) {
|
||||
if (!manifest.capabilities.includes("agents.managed")) {
|
||||
ctx.addIssue({
|
||||
|
||||
Reference in new issue
Block a user