Merge qualified backup expiration parent into GitHub connection work

Co-Authored-By: Paperclip <noreply@paperclip.ing>

* commit 'aae32f2f493848199f6cb8c0a9996af3ee0061b1': (30 commits)
  Scope status-card refresh tasks to their claim revision
  test(chat): retain completion identity before link metadata loads
  test(chat): locate completion through its rendered task link
  fix(chat): recover committed native Agent Chat replies (#18465)
  perf(heartbeat): drive retry promotion from durable deadlines (#18387)
  fix(ui): make the Coordinator composer footer opaque (#18455)
  fix(testops): verify unexpanded result job runs (#18462)
  test(server): observe restored Retry before draining unrelated work
  test(runner): own listener cleanup across setup failures
  test(runner): buffer upgrade frames until the wire subscribes
  fix(runner): preserve OpenCode written-answer defaults (#18456)
  fix(native): fence retries when replaying an audited Stop (#18457)
  test: await async outcomes and drive saved deadlines deterministically (#18416)
  fix(ui): retain startup autosave through session recovery (#18412)
  perf(server): recover independent native replies concurrently (#18421)
  perf(chat): scope task questions and batch inbox queue checks (#18422)
  fix(native): recover controllers across webserver replacement (#18343)
  fix(ui): restore task document authoring and add persistence journey (#18356)
  fix(tools): stabilize tied profile entry order (#18427)
  fix(adapter-utils): tolerate entries removed during workspace snapshots (#18426)
  ...
This commit is contained in:
DottaandPaperclip committed 2026-10-31 09:41:51 -05:00
commit f522ab07e2
484 files changed
+33834 -1620

No files matched your search

+1 -1
View File
@@ -42,7 +42,7 @@ export function agentHarnessType(adapterType: string, config: Record<string, unk
if (config.provider === "opencode") return "opencode_local";
if (config.provider === "acpx") {
const agent = config.acpxAgent ?? "claude";
return ({ codex: "codex_local", claude: "claude_local", grok: "grok_local", cursor: "cursor", pi: "pi_local", antigravity: "antigravity_runtime" } as Record<string, string>)[String(agent)] ?? `acpx:${String(agent)}`;
return ({ codex: "codex_local", claude: "claude_local", grok: "grok_local", cursor: "cursor", pi: "pi_local", kimi: "kimi_local", antigravity: "antigravity_runtime" } as Record<string, string>)[String(agent)] ?? `acpx:${String(agent)}`;
}
return String(config.provider);
}
@@ -5,11 +5,26 @@ import {
googleWorkspaceGrantedScopes, googleWorkspaceToolTarget, isGoogleWorkspaceToolGranted,
googleWorkspaceServiceGranted, isGoogleWorkspaceScopeGrant,
googleWorkspaceSelectedScopes, googleWorkspaceEffectiveScopes, GOOGLE_WORKSPACE_DEFAULT_SELECTION,
googleWorkspaceDraftRequestedScopes,
} from "./google-workspace-connectors.js";
const scope = (value: string) => `https://www.googleapis.com/auth/${value}`;
describe("combined Google Workspace consent", () => {
it("restores draft intent only for its exact identity and current service scopes", () => {
const binding = { companyId: "company", connectionId: "connection", actorType: "user", actorId: "owner",
grantKind: "user" as const, subjectId: "owner" };
const draft = { version: 1, ...binding, requestedScopes: [scope("gmail.readonly")] };
expect(googleWorkspaceDraftRequestedScopes(draft, binding)).toEqual([scope("gmail.readonly")]);
for (const field of ["companyId", "connectionId", "actorType", "actorId", "grantKind", "subjectId"] as const) {
expect(googleWorkspaceDraftRequestedScopes({ ...draft, [field]: "different" }, binding)).toBeNull();
}
for (const requestedScopes of [[], [scope("chat.messages.readonly")], [scope("contacts.readonly")], [scope("gmail.send")], "gmail.readonly"]) {
expect(googleWorkspaceDraftRequestedScopes({ ...draft, requestedScopes }, binding)).toBeNull();
}
expect(googleWorkspaceDraftRequestedScopes(undefined, binding)).toBeNull();
});
it("defaults to Gmail, combined Drive, and Calendar write scopes without Chat or People", () => {
const selected = googleWorkspaceSelectedScopes(GOOGLE_WORKSPACE_DEFAULT_SELECTION);
expect(selected).toHaveLength(9);
@@ -48,6 +48,31 @@ export function googleWorkspaceSelectionForScopes(scopes: readonly string[]): Go
return selection;
}
export interface GoogleWorkspaceDraftBinding {
companyId: string;
connectionId: string;
actorType: string | null;
actorId: string | null;
grantKind: "user" | "agent" | "organization";
subjectId: string | null;
}
export function googleWorkspaceDraftRequestedScopes(
value: unknown,
binding: GoogleWorkspaceDraftBinding,
): string[] | null {
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
const draft = value as Record<string, unknown>;
if (!binding.actorType || !binding.actorId || draft.version !== 1
|| Object.entries(binding).some(([key, expected]) => draft[key] !== expected)) return null;
const scopes = draft.requestedScopes;
const allowed = new Set(GOOGLE_WORKSPACE_SERVICE_GROUPS.flatMap(group =>
[...group.read, ...group.write].flatMap(profile => GOOGLE_WORKSPACE_CONNECTOR_PROFILES[profile].scopes)));
if (!Array.isArray(scopes) || scopes.length === 0 || scopes.length > allowed.size
|| scopes.some(scope => typeof scope !== "string" || !allowed.has(scope))) return null;
return [...new Set(scopes)].sort();
}
const auth = (scope: string) => `https://www.googleapis.com/auth/${scope}`;
const SERVICE_PROFILES: Readonly<Record<Exclude<GoogleWorkspaceConnectorProfileId, "workspace.all">, {
+2
View File
@@ -1993,6 +1993,8 @@ export {
issueCommentMetadataSectionSchema,
issueCommentMetadataSchema,
addIssueCommentSchema,
sendChatMessageSchema,
markIssueReadSchema,
issueThreadInteractionStatusSchema,
issueThreadInteractionKindSchema,
issueThreadInteractionContinuationPolicySchema,
+6
View File
@@ -1178,6 +1178,12 @@ export interface IssueCommentMetadataSection {
export interface IssueCommentMetadata {
version: 1;
chatMessage?: {
sourceTaskId: string;
sourceTaskIdentifier: string;
sourceRunId: string;
contentHash: string;
};
/** Producer-classified diagnostics; task interruption UI owns system repair. */
recoveryResponsibility?: "system" | "user";
/** Inbound channel attribution; never an authorization input. */
+2
View File
@@ -460,6 +460,8 @@ export {
issueCommentMetadataSectionSchema,
issueCommentMetadataSchema,
addIssueCommentSchema,
sendChatMessageSchema,
markIssueReadSchema,
issueThreadInteractionStatusSchema,
issueThreadInteractionKindSchema,
issueThreadInteractionCanonicalResolverPolicySchema,
+13
View File
@@ -1101,6 +1101,12 @@ export const issueCommentMetadataSectionSchema = z
export const issueCommentMetadataSchema = z
.object({
version: z.literal(1),
chatMessage: z.object({
sourceTaskId: z.uuid(),
sourceTaskIdentifier: z.string().min(1).max(80),
sourceRunId: z.uuid(),
contentHash: z.string().regex(/^[a-f0-9]{64}$/),
}).strict().optional(),
recoveryResponsibility: z.enum(["system", "user"]).optional(),
sourceChannel: z.enum(CHAT_PROVIDERS).optional(),
sourceRunId: z.string().guid().nullable().optional(),
@@ -1125,6 +1131,13 @@ export const issueCommentMetadataSchema = z
export type IssueCommentMetadata = z.infer<typeof issueCommentMetadataSchema>;
export const sendChatMessageSchema = z.object({
body: multilineTextSchema.pipe(z.string().trim().min(1).max(20000)),
idempotencyKey: z.string().trim().min(1).max(240),
}).strict();
export const markIssueReadSchema = z.object({ throughCommentId: z.uuid().optional() }).strict();
export const addIssueCommentSchema = z.object({
clientRequestId: z.string().uuid().optional(),
body: multilineTextSchema.pipe(z.string().min(1)),