@vercel/factory 0.0.5 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @vercel/factory
2
2
 
3
- The framework for building Agent Factories: schemas, state machines, store drivers, dispatch, agent tools, and connectors for auditable autonomous repository work.
3
+ The Factory Development Kit: typed constructs, workflows, schemas, execution contracts,
4
+ persistence, agent tools, and provider adapters for durable, auditable software factories.
4
5
 
5
- See the [repository README](../../README.md) for the project overview and development instructions.
6
+ The FDK extends Eve incrementally. Durable workflows retain authority over policy, budgets,
7
+ state transitions, retries, and external effects while agents and coding harnesses return bounded
8
+ results. The V1 reference runtime uses Postgres, Blob, AI SDK `HarnessAgent`, and Vercel Sandbox,
9
+ with independent verification and human-owned merges.
10
+
11
+ See the [repository README](../../README.md) for development instructions and the
12
+ [architecture](../../docs/factory-architecture.md) for the complete contract.
@@ -23,12 +23,12 @@ declare const levelSchema: z.ZodEnum<{
23
23
  high: "high";
24
24
  }>;
25
25
  declare const changeStateSchema: z.ZodEnum<{
26
+ rolled_back: "rolled_back";
26
27
  verifying: "verifying";
27
28
  ready: "ready";
28
29
  merged: "merged";
29
30
  deployed: "deployed";
30
31
  rolled_out: "rolled_out";
31
- rolled_back: "rolled_back";
32
32
  closed: "closed";
33
33
  }>;
34
34
  declare const changeEvidenceSchema: z.ZodObject<{
@@ -67,14 +67,15 @@ declare const changeSchema: z.ZodObject<{
67
67
  previewUrl: z.ZodOptional<z.ZodURL>;
68
68
  }, z.core.$strict>;
69
69
  state: z.ZodEnum<{
70
+ rolled_back: "rolled_back";
70
71
  verifying: "verifying";
71
72
  ready: "ready";
72
73
  merged: "merged";
73
74
  deployed: "deployed";
74
75
  rolled_out: "rolled_out";
75
- rolled_back: "rolled_back";
76
76
  closed: "closed";
77
77
  }>;
78
+ mergeSha: z.ZodOptional<z.ZodString>;
78
79
  decidedBy: z.ZodOptional<z.ZodString>;
79
80
  createdAt: z.ZodISODateTime;
80
81
  updatedAt: z.ZodISODateTime;
@@ -147,12 +148,12 @@ type Repository = z.infer<typeof repositorySchema>;
147
148
  declare const standardTaskKinds: readonly ["code_change", "verification", "investigation", "question"];
148
149
  declare const taskKindSchema: z.ZodString;
149
150
  declare const taskStateSchema: z.ZodEnum<{
150
- queued: "queued";
151
- running: "running";
152
- verifying: "verifying";
153
151
  succeeded: "succeeded";
154
152
  failed: "failed";
155
153
  needs_human: "needs_human";
154
+ queued: "queued";
155
+ running: "running";
156
+ verifying: "verifying";
156
157
  cancelled: "cancelled";
157
158
  }>;
158
159
  declare const taskApprovalSchema: z.ZodEnum<{
@@ -184,12 +185,12 @@ declare const taskSchema: z.ZodObject<{
184
185
  kind: z.ZodString;
185
186
  area: z.ZodOptional<z.ZodString>;
186
187
  state: z.ZodEnum<{
187
- queued: "queued";
188
- running: "running";
189
- verifying: "verifying";
190
188
  succeeded: "succeeded";
191
189
  failed: "failed";
192
190
  needs_human: "needs_human";
191
+ queued: "queued";
192
+ running: "running";
193
+ verifying: "verifying";
193
194
  cancelled: "cancelled";
194
195
  }>;
195
196
  approval: z.ZodOptional<z.ZodEnum<{
@@ -281,7 +282,7 @@ interface CreateChangeInput {
281
282
  confidence: Level;
282
283
  evidence: Change["evidence"];
283
284
  }
284
- type ChangePatch = Partial<Pick<Change, "confidence" | "evidence" | "decidedBy">>;
285
+ type ChangePatch = Partial<Pick<Change, "confidence" | "evidence" | "decidedBy" | "mergeSha">>;
285
286
  interface ChangeTransitionOptions {
286
287
  patch?: ChangePatch;
287
288
  reason?: string;
@@ -507,4 +508,4 @@ interface ApprovalSubject {
507
508
  declare function requiresApproval(policy: ApprovalPolicy, subject: ApprovalSubject): boolean;
508
509
  //#endregion
509
510
  export { ReceiptPhase as $, TaskPatch as A, taskDevboxSchema as B, ChangeTransitionOptions as C, changeIdSchema as Ct, CreateTaskInput as D, repositoryIdsSchema as Dt, CreateStoresOptions as E, repositoryIdSchema as Et, TaskKind as F, taskStateSchema as G, taskOriginSchema as H, TaskState as I, repositorySchema as J, Repository as K, harnessSchema as L, createStores as M, Task as N, DecideSignalOptions as O, signalIdSchema as Ot, TaskApproval as P, ReceiptKind as Q, standardTaskKinds as R, ChangePatch as S, TaskId as St, CreateSignalInput as T, receiptIdSchema as Tt, taskQuestionSchema as U, taskKindSchema as V, taskSchema as W, Cost as X, repositorySlugSchema as Y, Receipt as Z, findingVerificationMethodSchema as _, ChangeId as _t, approvalRuleSchema as a, receiptStateSchema as at, ApprovalDecision as b, RepositoryId as bt, Finding as c, standardReceiptStates as ct, FindingVerification as d, ChangeState as dt, ReceiptState as et, findingCategorySchema as f, Level as ft, findingVerificationLevelSchema as g, levelSchema as gt, findingSchema as h, changeStateSchema as ht, approvalPolicySchema as i, receiptSchema as it, TaskTransitionOptions as j, FactoryStores as k, taskIdSchema as kt, FindingCategory as l, Change as lt, findingPrioritySchema as m, changeSchema as mt, ApprovalRule as n, receiptKindSchema as nt, defaultApprovalPolicy as o, standardReceiptKinds as ot, findingFingerprint as p, changeEvidenceSchema as pt, RepositorySlug as q, ApprovalSubject as r, receiptPhaseSchema as rt, requiresApproval as s, standardReceiptPhases as st, ApprovalPolicy as t, costSchema as tt, FindingPriority as u, ChangeEvidence as ut, findingVerificationSchema as v, FactoryId as vt, CreateChangeInput as w, factoryIdSchema as wt, ApprovalError as x, SignalId as xt, AppendReceiptInput as y, ReceiptId as yt, taskApprovalSchema as z };
510
- //# sourceMappingURL=approval-h5aj8HYN.d.mts.map
511
+ //# sourceMappingURL=approval-qkxww0wJ.d.mts.map
@@ -1,2 +1,2 @@
1
- import { a as NormalizedSignal, c as communicationEventSchema, d as createCommunicationRouter, i as CommunicationRouter, l as communicationOutcomeSchema, n as CommunicationEvent, o as SignalNormalizer, r as CommunicationOutcome, s as WebhookEvent, t as CommunicationAdapter, u as communicationOutcomes } from "../index-WNGZJRRH.mjs";
1
+ import { a as NormalizedSignal, c as communicationEventSchema, d as createCommunicationRouter, i as CommunicationRouter, l as communicationOutcomeSchema, n as CommunicationEvent, o as SignalNormalizer, r as CommunicationOutcome, s as WebhookEvent, t as CommunicationAdapter, u as communicationOutcomes } from "../index-DUb-U5cy.mjs";
2
2
  export { CommunicationAdapter, CommunicationEvent, CommunicationOutcome, CommunicationRouter, NormalizedSignal, SignalNormalizer, WebhookEvent, communicationEventSchema, communicationOutcomeSchema, communicationOutcomes, createCommunicationRouter };
@@ -1,4 +1,4 @@
1
- import { i as repositoryIdSchema, s as taskIdSchema, t as changeIdSchema, u as replyToSchema } from "../id-DwCihQr4.mjs";
1
+ import { a as repositoryIdsSchema, s as taskIdSchema, t as changeIdSchema, u as replyToSchema } from "../id-DwCihQr4.mjs";
2
2
  import { z } from "zod";
3
3
  //#region src/connectors/index.ts
4
4
  const communicationOutcomes = [
@@ -17,7 +17,7 @@ const communicationOutcomes = [
17
17
  const communicationOutcomeSchema = z.enum(communicationOutcomes).describe("Lifecycle outcome a connector should render and deliver.");
18
18
  const communicationEventSchema = z.strictObject({
19
19
  eventId: z.string().min(1).describe("Stable idempotency key for this delivery."),
20
- repositoryId: repositoryIdSchema,
20
+ repositoryIds: repositoryIdsSchema,
21
21
  taskId: taskIdSchema.optional(),
22
22
  changeId: changeIdSchema.optional(),
23
23
  replyTo: replyToSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/connectors/index.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { changeIdSchema, repositoryIdSchema, taskIdSchema } from \"../schema/id\";\nimport { replyToSchema } from \"../schema/common\";\nimport type { ReplyTo } from \"../schema/common\";\nimport type { SignalSource } from \"../schema/signal\";\n\nexport interface WebhookEvent {\n deliveryId: string;\n event: string;\n payload: unknown;\n}\n\nexport interface NormalizedSignal<TSource extends SignalSource = SignalSource> {\n source: TSource;\n deliveryId: string;\n replyTo: ReplyTo;\n payload: unknown;\n}\n\nexport type SignalNormalizer<TSignal extends NormalizedSignal = NormalizedSignal> = (\n event: WebhookEvent,\n) => TSignal | null;\n\nexport const communicationOutcomes = [\n \"accepted\",\n \"started\",\n \"succeeded\",\n \"failed\",\n \"needs_human\",\n \"question\",\n \"digest\",\n \"rolled_back\",\n \"budget_warning\",\n \"budget_exhausted\",\n \"message\",\n] as const;\n\nexport const communicationOutcomeSchema = z\n .enum(communicationOutcomes)\n .describe(\"Lifecycle outcome a connector should render and deliver.\");\n\nexport const communicationEventSchema = z.strictObject({\n eventId: z.string().min(1).describe(\"Stable idempotency key for this delivery.\"),\n repositoryId: repositoryIdSchema,\n taskId: taskIdSchema.optional(),\n changeId: changeIdSchema.optional(),\n replyTo: replyToSchema,\n outcome: communicationOutcomeSchema,\n data: z\n .record(z.string(), z.unknown())\n .describe(\"Outcome-specific data rendered by the selected connector.\"),\n});\n\nexport type CommunicationOutcome = z.infer<typeof communicationOutcomeSchema>;\nexport type CommunicationEvent = z.infer<typeof communicationEventSchema>;\n\nexport interface CommunicationAdapter {\n readonly channel: string;\n deliver(event: CommunicationEvent): Promise<void>;\n}\n\nexport interface CommunicationRouter {\n readonly channels: readonly string[];\n deliver(event: CommunicationEvent): Promise<void>;\n}\n\nexport function createCommunicationRouter(\n adapters: readonly CommunicationAdapter[],\n): CommunicationRouter {\n const byChannel = new Map<string, CommunicationAdapter>();\n for (const adapter of adapters) {\n const channel = adapter.channel.trim();\n if (channel.length === 0) {\n throw new Error(\"Communication adapter channel is required.\");\n }\n if (byChannel.has(channel)) {\n throw new Error(`Communication adapter ${channel} is registered more than once.`);\n }\n byChannel.set(channel, adapter);\n }\n const channels = Object.freeze([...byChannel.keys()]);\n\n return Object.freeze({\n channels,\n async deliver(input: CommunicationEvent): Promise<void> {\n const event = communicationEventSchema.parse(input);\n const adapter = byChannel.get(event.replyTo.channel);\n if (adapter === undefined) {\n throw new Error(`No communication adapter is registered for ${event.replyTo.channel}.`);\n }\n await adapter.deliver(event);\n },\n });\n}\n"],"mappings":";;;AAuBA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAa,6BAA6B,EACvC,KAAK,qBAAqB,CAAC,CAC3B,SAAS,0DAA0D;AAEtE,MAAa,2BAA2B,EAAE,aAAa;CACrD,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,2CAA2C;CAC/E,cAAc;CACd,QAAQ,aAAa,SAAS;CAC9B,UAAU,eAAe,SAAS;CAClC,SAAS;CACT,SAAS;CACT,MAAM,EACH,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAC/B,SAAS,2DAA2D;AACzE,CAAC;AAeD,SAAgB,0BACd,UACqB;CACrB,MAAM,4BAAY,IAAI,IAAkC;CACxD,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,UAAU,QAAQ,QAAQ,KAAK;EACrC,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,4CAA4C;EAE9D,IAAI,UAAU,IAAI,OAAO,GACvB,MAAM,IAAI,MAAM,yBAAyB,QAAQ,+BAA+B;EAElF,UAAU,IAAI,SAAS,OAAO;CAChC;CACA,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG,UAAU,KAAK,CAAC,CAAC;CAEpD,OAAO,OAAO,OAAO;EACnB;EACA,MAAM,QAAQ,OAA0C;GACtD,MAAM,QAAQ,yBAAyB,MAAM,KAAK;GAClD,MAAM,UAAU,UAAU,IAAI,MAAM,QAAQ,OAAO;GACnD,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MAAM,8CAA8C,MAAM,QAAQ,QAAQ,EAAE;GAExF,MAAM,QAAQ,QAAQ,KAAK;EAC7B;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/connectors/index.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { changeIdSchema, repositoryIdsSchema, taskIdSchema } from \"../schema/id\";\nimport { replyToSchema } from \"../schema/common\";\nimport type { ReplyTo } from \"../schema/common\";\nimport type { SignalSource } from \"../schema/signal\";\n\nexport interface WebhookEvent {\n deliveryId: string;\n event: string;\n payload: unknown;\n}\n\nexport interface NormalizedSignal<TSource extends SignalSource = SignalSource> {\n source: TSource;\n deliveryId: string;\n replyTo: ReplyTo;\n payload: unknown;\n}\n\nexport type SignalNormalizer<TSignal extends NormalizedSignal = NormalizedSignal> = (\n event: WebhookEvent,\n) => TSignal | null;\n\nexport const communicationOutcomes = [\n \"accepted\",\n \"started\",\n \"succeeded\",\n \"failed\",\n \"needs_human\",\n \"question\",\n \"digest\",\n \"rolled_back\",\n \"budget_warning\",\n \"budget_exhausted\",\n \"message\",\n] as const;\n\nexport const communicationOutcomeSchema = z\n .enum(communicationOutcomes)\n .describe(\"Lifecycle outcome a connector should render and deliver.\");\n\nexport const communicationEventSchema = z.strictObject({\n eventId: z.string().min(1).describe(\"Stable idempotency key for this delivery.\"),\n repositoryIds: repositoryIdsSchema,\n taskId: taskIdSchema.optional(),\n changeId: changeIdSchema.optional(),\n replyTo: replyToSchema,\n outcome: communicationOutcomeSchema,\n data: z\n .record(z.string(), z.unknown())\n .describe(\"Outcome-specific data rendered by the selected connector.\"),\n});\n\nexport type CommunicationOutcome = z.infer<typeof communicationOutcomeSchema>;\nexport type CommunicationEvent = z.infer<typeof communicationEventSchema>;\n\nexport interface CommunicationAdapter {\n readonly channel: string;\n deliver(event: CommunicationEvent): Promise<void>;\n}\n\nexport interface CommunicationRouter {\n readonly channels: readonly string[];\n deliver(event: CommunicationEvent): Promise<void>;\n}\n\nexport function createCommunicationRouter(\n adapters: readonly CommunicationAdapter[],\n): CommunicationRouter {\n const byChannel = new Map<string, CommunicationAdapter>();\n for (const adapter of adapters) {\n const channel = adapter.channel.trim();\n if (channel.length === 0) {\n throw new Error(\"Communication adapter channel is required.\");\n }\n if (byChannel.has(channel)) {\n throw new Error(`Communication adapter ${channel} is registered more than once.`);\n }\n byChannel.set(channel, adapter);\n }\n const channels = Object.freeze([...byChannel.keys()]);\n\n return Object.freeze({\n channels,\n async deliver(input: CommunicationEvent): Promise<void> {\n const event = communicationEventSchema.parse(input);\n const adapter = byChannel.get(event.replyTo.channel);\n if (adapter === undefined) {\n throw new Error(`No communication adapter is registered for ${event.replyTo.channel}.`);\n }\n await adapter.deliver(event);\n },\n });\n}\n"],"mappings":";;;AAuBA,MAAa,wBAAwB;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAa,6BAA6B,EACvC,KAAK,qBAAqB,CAAC,CAC3B,SAAS,0DAA0D;AAEtE,MAAa,2BAA2B,EAAE,aAAa;CACrD,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,2CAA2C;CAC/E,eAAe;CACf,QAAQ,aAAa,SAAS;CAC9B,UAAU,eAAe,SAAS;CAClC,SAAS;CACT,SAAS;CACT,MAAM,EACH,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAC/B,SAAS,2DAA2D;AACzE,CAAC;AAeD,SAAgB,0BACd,UACqB;CACrB,MAAM,4BAAY,IAAI,IAAkC;CACxD,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,UAAU,QAAQ,QAAQ,KAAK;EACrC,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,4CAA4C;EAE9D,IAAI,UAAU,IAAI,OAAO,GACvB,MAAM,IAAI,MAAM,yBAAyB,QAAQ,+BAA+B;EAElF,UAAU,IAAI,SAAS,OAAO;CAChC;CACA,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG,UAAU,KAAK,CAAC,CAAC;CAEpD,OAAO,OAAO,OAAO;EACnB;EACA,MAAM,QAAQ,OAA0C;GACtD,MAAM,QAAQ,yBAAyB,MAAM,KAAK;GAClD,MAAM,UAAU,UAAU,IAAI,MAAM,QAAQ,OAAO;GACnD,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MAAM,8CAA8C,MAAM,QAAQ,QAAQ,EAAE;GAExF,MAAM,QAAQ,QAAQ,KAAK;EAC7B;CACF,CAAC;AACH"}
@@ -1,5 +1,35 @@
1
- import { a as NormalizedSignal } from "../index-WNGZJRRH.mjs";
1
+ import { a as NormalizedSignal, n as CommunicationEvent, t as CommunicationAdapter } from "../index-DUb-U5cy.mjs";
2
2
  //#region src/connectors/slack.d.ts
3
+ interface SlackCommunicationDelivery {
4
+ eventId: string;
5
+ clientMessageId: string;
6
+ text: string;
7
+ target: {
8
+ type: "owner";
9
+ } | {
10
+ type: "thread";
11
+ channelId: string;
12
+ threadTs: string;
13
+ };
14
+ }
15
+ interface SlackCommunicationAdapter extends CommunicationAdapter {
16
+ readonly channel: "slack";
17
+ render(event: CommunicationEvent): string;
18
+ }
19
+ interface SlackCommunicationAdapterOptions {
20
+ send(delivery: SlackCommunicationDelivery): Promise<void>;
21
+ render?: (event: CommunicationEvent) => string;
22
+ }
23
+ interface SlackReplyTarget {
24
+ channelId: string;
25
+ threadTs: string;
26
+ }
27
+ /** Parse Eve's Slack continuation token into its channel and thread target. */
28
+ declare function parseSlackReplyAddress(address: string): SlackReplyTarget;
29
+ /** Render a provider-neutral communication event as plain Slack text. */
30
+ declare function renderSlackCommunicationEvent(input: CommunicationEvent): string;
31
+ /** Bind Slack rendering and delivery to the channel-neutral communication contract. */
32
+ declare function createSlackCommunicationAdapter(options: SlackCommunicationAdapterOptions): SlackCommunicationAdapter;
3
33
  interface SlackMessageEvent {
4
34
  teamId: string;
5
35
  channelId: string;
@@ -39,5 +69,5 @@ type SlackRepositorySelection = {
39
69
  */
40
70
  declare function selectSlackRepository(text: string, repositories: readonly string[]): SlackRepositorySelection;
41
71
  //#endregion
42
- export { SlackMessageEvent, SlackMessageSignal, SlackRepositorySelection, normalizeSlackMessage, selectSlackRepository };
72
+ export { SlackCommunicationAdapter, SlackCommunicationAdapterOptions, SlackCommunicationDelivery, SlackMessageEvent, SlackMessageSignal, SlackReplyTarget, SlackRepositorySelection, createSlackCommunicationAdapter, normalizeSlackMessage, parseSlackReplyAddress, renderSlackCommunicationEvent, selectSlackRepository };
43
73
  //# sourceMappingURL=slack.d.mts.map
@@ -1,4 +1,94 @@
1
+ import { communicationEventSchema } from "./index.mjs";
2
+ import { createHash } from "node:crypto";
1
3
  //#region src/connectors/slack.ts
4
+ const slackOutcomeLabels = {
5
+ accepted: "Request accepted",
6
+ started: "Work started",
7
+ succeeded: "Work completed",
8
+ failed: "Work failed",
9
+ needs_human: "Human action required",
10
+ question: "Question requires an answer",
11
+ digest: "Factory digest",
12
+ rolled_back: "Change rolled back",
13
+ budget_warning: "Factory budget warning",
14
+ budget_exhausted: "Factory budget exhausted",
15
+ message: "Factory update"
16
+ };
17
+ const slackDetailFields = [
18
+ "title",
19
+ "message",
20
+ "summary",
21
+ "question",
22
+ "requestedAction",
23
+ "reason",
24
+ "url"
25
+ ];
26
+ const slackListFields = ["items", "options"];
27
+ const slackTextLimit = 12e3;
28
+ const slackOwnerOutcomes = /* @__PURE__ */ new Set([
29
+ "digest",
30
+ "budget_warning",
31
+ "budget_exhausted"
32
+ ]);
33
+ /** Parse Eve's Slack continuation token into its channel and thread target. */
34
+ function parseSlackReplyAddress(address) {
35
+ const separator = address.indexOf(":");
36
+ const channelId = address.slice(0, separator);
37
+ const threadTs = address.slice(separator + 1);
38
+ if (separator <= 0 || !/^[A-Z][A-Z0-9]+$/.test(channelId) || !/^\d+\.\d+$/.test(threadTs)) throw new Error(`Invalid Slack reply address: ${address}.`);
39
+ return {
40
+ channelId,
41
+ threadTs
42
+ };
43
+ }
44
+ /** Render a provider-neutral communication event as plain Slack text. */
45
+ function renderSlackCommunicationEvent(input) {
46
+ const event = communicationEventSchema.parse(input);
47
+ const headline = slackOutcomeLabels[event.outcome];
48
+ const details = slackDetailFields.flatMap((field) => {
49
+ const value = event.data[field];
50
+ return typeof value === "string" && value.trim() !== "" ? [value.trim()] : [];
51
+ });
52
+ const lists = slackListFields.flatMap((field) => {
53
+ const value = event.data[field];
54
+ if (!Array.isArray(value)) return [];
55
+ return value.flatMap((item) => typeof item === "string" && item.trim() !== "" ? [`- ${item.trim()}`] : []);
56
+ });
57
+ const text = [headline, .../* @__PURE__ */ new Set([...details, ...lists])].join("\n");
58
+ return text.length <= slackTextLimit ? text : `${text.slice(0, 11999)}…`;
59
+ }
60
+ function slackClientMessageId(eventId) {
61
+ const digest = createHash("sha256").update(eventId).digest("hex").slice(0, 32);
62
+ return [
63
+ digest.slice(0, 8),
64
+ digest.slice(8, 12),
65
+ digest.slice(12, 16),
66
+ digest.slice(16, 20),
67
+ digest.slice(20)
68
+ ].join("-");
69
+ }
70
+ /** Bind Slack rendering and delivery to the channel-neutral communication contract. */
71
+ function createSlackCommunicationAdapter(options) {
72
+ const render = options.render ?? renderSlackCommunicationEvent;
73
+ return Object.freeze({
74
+ channel: "slack",
75
+ render,
76
+ async deliver(input) {
77
+ const event = communicationEventSchema.parse(input);
78
+ if (event.replyTo.channel !== "slack") throw new Error(`Slack communication adapter cannot deliver to ${event.replyTo.channel}.`);
79
+ const target = slackOwnerOutcomes.has(event.outcome) ? { type: "owner" } : {
80
+ type: "thread",
81
+ ...parseSlackReplyAddress(event.replyTo.address)
82
+ };
83
+ await options.send({
84
+ eventId: event.eventId,
85
+ clientMessageId: slackClientMessageId(event.eventId),
86
+ text: render(event),
87
+ target
88
+ });
89
+ }
90
+ });
91
+ }
2
92
  /** Normalize an Eve-verified Slack message after the caller resolves its repository. */
3
93
  function normalizeSlackMessage(event) {
4
94
  return {
@@ -45,6 +135,6 @@ function selectSlackRepository(text, repositories) {
45
135
  return { status: "required" };
46
136
  }
47
137
  //#endregion
48
- export { normalizeSlackMessage, selectSlackRepository };
138
+ export { createSlackCommunicationAdapter, normalizeSlackMessage, parseSlackReplyAddress, renderSlackCommunicationEvent, selectSlackRepository };
49
139
 
50
140
  //# sourceMappingURL=slack.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"slack.mjs","names":[],"sources":["../../src/connectors/slack.ts"],"sourcesContent":["import type { NormalizedSignal } from \"./index\";\n\nexport interface SlackMessageEvent {\n teamId: string;\n channelId: string;\n messageTs: string;\n threadTs: string;\n actorId: string;\n text: string;\n replyAddress: string;\n repositorySlug: string;\n payload: unknown;\n}\n\nexport interface SlackMessageSignal extends NormalizedSignal<\"slack\"> {\n repositorySlug: string;\n message: {\n teamId: string;\n channelId: string;\n messageTs: string;\n threadTs: string;\n actorId: string;\n text: string;\n };\n}\n\n/** Normalize an Eve-verified Slack message after the caller resolves its repository. */\nexport function normalizeSlackMessage(event: SlackMessageEvent): SlackMessageSignal {\n return {\n source: \"slack\",\n deliveryId: `${event.teamId}:${event.channelId}:${event.messageTs}`,\n repositorySlug: event.repositorySlug.toLowerCase(),\n replyTo: { channel: \"slack\", address: event.replyAddress },\n message: {\n teamId: event.teamId,\n channelId: event.channelId,\n messageTs: event.messageTs,\n threadTs: event.threadTs,\n actorId: event.actorId,\n text: event.text,\n },\n payload: event.payload,\n };\n}\n\nexport type SlackRepositorySelection =\n | { status: \"selected\"; repositorySlug: string }\n | { status: \"required\" }\n | { status: \"ambiguous\"; repositorySlugs: readonly string[] };\n\n/**\n * Select the only configured repository, or require an explicit owner/name\n * when a Slack surface fronts more than one repository.\n */\nexport function selectSlackRepository(\n text: string,\n repositories: readonly string[],\n): SlackRepositorySelection {\n const normalized = [...new Set(repositories.map((slug) => slug.toLowerCase()))];\n if (normalized.length === 1) {\n return { status: \"selected\", repositorySlug: normalized[0]! };\n }\n\n const matches = normalized.filter((slug) => {\n const escaped = slug.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`(^|[^a-z0-9._/-])${escaped}($|[^a-z0-9._/-])`, \"i\").test(text);\n });\n if (matches.length === 1) {\n return { status: \"selected\", repositorySlug: matches[0]! };\n }\n if (matches.length > 1) {\n return { status: \"ambiguous\", repositorySlugs: matches };\n }\n return { status: \"required\" };\n}\n"],"mappings":";;AA2BA,SAAgB,sBAAsB,OAA8C;CAClF,OAAO;EACL,QAAQ;EACR,YAAY,GAAG,MAAM,OAAO,GAAG,MAAM,UAAU,GAAG,MAAM;EACxD,gBAAgB,MAAM,eAAe,YAAY;EACjD,SAAS;GAAE,SAAS;GAAS,SAAS,MAAM;EAAa;EACzD,SAAS;GACP,QAAQ,MAAM;GACd,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,UAAU,MAAM;GAChB,SAAS,MAAM;GACf,MAAM,MAAM;EACd;EACA,SAAS,MAAM;CACjB;AACF;;;;;AAWA,SAAgB,sBACd,MACA,cAC0B;CAC1B,MAAM,aAAa,CAAC,GAAG,IAAI,IAAI,aAAa,KAAK,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC;CAC9E,IAAI,WAAW,WAAW,GACxB,OAAO;EAAE,QAAQ;EAAY,gBAAgB,WAAW;CAAI;CAG9D,MAAM,UAAU,WAAW,QAAQ,SAAS;EAC1C,MAAM,UAAU,KAAK,QAAQ,uBAAuB,MAAM;EAC1D,OAAO,IAAI,OAAO,oBAAoB,QAAQ,oBAAoB,GAAG,CAAC,CAAC,KAAK,IAAI;CAClF,CAAC;CACD,IAAI,QAAQ,WAAW,GACrB,OAAO;EAAE,QAAQ;EAAY,gBAAgB,QAAQ;CAAI;CAE3D,IAAI,QAAQ,SAAS,GACnB,OAAO;EAAE,QAAQ;EAAa,iBAAiB;CAAQ;CAEzD,OAAO,EAAE,QAAQ,WAAW;AAC9B"}
1
+ {"version":3,"file":"slack.mjs","names":[],"sources":["../../src/connectors/slack.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n communicationEventSchema,\n type CommunicationAdapter,\n type CommunicationEvent,\n type CommunicationOutcome,\n type NormalizedSignal,\n} from \"./index\";\n\nconst slackOutcomeLabels: Record<CommunicationOutcome, string> = {\n accepted: \"Request accepted\",\n started: \"Work started\",\n succeeded: \"Work completed\",\n failed: \"Work failed\",\n needs_human: \"Human action required\",\n question: \"Question requires an answer\",\n digest: \"Factory digest\",\n rolled_back: \"Change rolled back\",\n budget_warning: \"Factory budget warning\",\n budget_exhausted: \"Factory budget exhausted\",\n message: \"Factory update\",\n};\n\nconst slackDetailFields = [\"title\", \"message\", \"summary\", \"question\", \"requestedAction\", \"reason\", \"url\"] as const;\nconst slackListFields = [\"items\", \"options\"] as const;\nconst slackTextLimit = 12_000;\nconst slackOwnerOutcomes = new Set<CommunicationOutcome>([\n \"digest\",\n \"budget_warning\",\n \"budget_exhausted\",\n]);\n\nexport interface SlackCommunicationDelivery {\n eventId: string;\n clientMessageId: string;\n text: string;\n target:\n | { type: \"owner\" }\n | { type: \"thread\"; channelId: string; threadTs: string };\n}\n\nexport interface SlackCommunicationAdapter extends CommunicationAdapter {\n readonly channel: \"slack\";\n render(event: CommunicationEvent): string;\n}\n\nexport interface SlackCommunicationAdapterOptions {\n send(delivery: SlackCommunicationDelivery): Promise<void>;\n render?: (event: CommunicationEvent) => string;\n}\n\nexport interface SlackReplyTarget {\n channelId: string;\n threadTs: string;\n}\n\n/** Parse Eve's Slack continuation token into its channel and thread target. */\nexport function parseSlackReplyAddress(address: string): SlackReplyTarget {\n const separator = address.indexOf(\":\");\n const channelId = address.slice(0, separator);\n const threadTs = address.slice(separator + 1);\n if (separator <= 0 || !/^[A-Z][A-Z0-9]+$/.test(channelId) || !/^\\d+\\.\\d+$/.test(threadTs)) {\n throw new Error(`Invalid Slack reply address: ${address}.`);\n }\n return { channelId, threadTs };\n}\n\n/** Render a provider-neutral communication event as plain Slack text. */\nexport function renderSlackCommunicationEvent(input: CommunicationEvent): string {\n const event = communicationEventSchema.parse(input);\n const headline = slackOutcomeLabels[event.outcome];\n const details = slackDetailFields.flatMap((field) => {\n const value = event.data[field];\n return typeof value === \"string\" && value.trim() !== \"\" ? [value.trim()] : [];\n });\n const lists = slackListFields.flatMap((field) => {\n const value = event.data[field];\n if (!Array.isArray(value)) return [];\n return value.flatMap((item) =>\n typeof item === \"string\" && item.trim() !== \"\" ? [`- ${item.trim()}`] : []\n );\n });\n const text = [headline, ...new Set([...details, ...lists])].join(\"\\n\");\n return text.length <= slackTextLimit ? text : `${text.slice(0, slackTextLimit - 1)}…`;\n}\n\nfunction slackClientMessageId(eventId: string): string {\n const digest = createHash(\"sha256\").update(eventId).digest(\"hex\").slice(0, 32);\n return [\n digest.slice(0, 8),\n digest.slice(8, 12),\n digest.slice(12, 16),\n digest.slice(16, 20),\n digest.slice(20),\n ].join(\"-\");\n}\n\n/** Bind Slack rendering and delivery to the channel-neutral communication contract. */\nexport function createSlackCommunicationAdapter(\n options: SlackCommunicationAdapterOptions,\n): SlackCommunicationAdapter {\n const render = options.render ?? renderSlackCommunicationEvent;\n return Object.freeze({\n channel: \"slack\" as const,\n render,\n async deliver(input: CommunicationEvent): Promise<void> {\n const event = communicationEventSchema.parse(input);\n if (event.replyTo.channel !== \"slack\") {\n throw new Error(`Slack communication adapter cannot deliver to ${event.replyTo.channel}.`);\n }\n const target = slackOwnerOutcomes.has(event.outcome)\n ? { type: \"owner\" as const }\n : { type: \"thread\" as const, ...parseSlackReplyAddress(event.replyTo.address) };\n await options.send({\n eventId: event.eventId,\n clientMessageId: slackClientMessageId(event.eventId),\n text: render(event),\n target,\n });\n },\n });\n}\n\nexport interface SlackMessageEvent {\n teamId: string;\n channelId: string;\n messageTs: string;\n threadTs: string;\n actorId: string;\n text: string;\n replyAddress: string;\n repositorySlug: string;\n payload: unknown;\n}\n\nexport interface SlackMessageSignal extends NormalizedSignal<\"slack\"> {\n repositorySlug: string;\n message: {\n teamId: string;\n channelId: string;\n messageTs: string;\n threadTs: string;\n actorId: string;\n text: string;\n };\n}\n\n/** Normalize an Eve-verified Slack message after the caller resolves its repository. */\nexport function normalizeSlackMessage(event: SlackMessageEvent): SlackMessageSignal {\n return {\n source: \"slack\",\n deliveryId: `${event.teamId}:${event.channelId}:${event.messageTs}`,\n repositorySlug: event.repositorySlug.toLowerCase(),\n replyTo: { channel: \"slack\", address: event.replyAddress },\n message: {\n teamId: event.teamId,\n channelId: event.channelId,\n messageTs: event.messageTs,\n threadTs: event.threadTs,\n actorId: event.actorId,\n text: event.text,\n },\n payload: event.payload,\n };\n}\n\nexport type SlackRepositorySelection =\n | { status: \"selected\"; repositorySlug: string }\n | { status: \"required\" }\n | { status: \"ambiguous\"; repositorySlugs: readonly string[] };\n\n/**\n * Select the only configured repository, or require an explicit owner/name\n * when a Slack surface fronts more than one repository.\n */\nexport function selectSlackRepository(\n text: string,\n repositories: readonly string[],\n): SlackRepositorySelection {\n const normalized = [...new Set(repositories.map((slug) => slug.toLowerCase()))];\n if (normalized.length === 1) {\n return { status: \"selected\", repositorySlug: normalized[0]! };\n }\n\n const matches = normalized.filter((slug) => {\n const escaped = slug.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(`(^|[^a-z0-9._/-])${escaped}($|[^a-z0-9._/-])`, \"i\").test(text);\n });\n if (matches.length === 1) {\n return { status: \"selected\", repositorySlug: matches[0]! };\n }\n if (matches.length > 1) {\n return { status: \"ambiguous\", repositorySlugs: matches };\n }\n return { status: \"required\" };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { c as Finding, k as FactoryStores, t as ApprovalPolicy } from "../approval-h5aj8HYN.mjs";
2
- import { d as GitHubReviewComment } from "../github-3sbHe-fo.mjs";
1
+ import { c as Finding, k as FactoryStores, t as ApprovalPolicy } from "../approval-qkxww0wJ.mjs";
2
+ import { d as GitHubReviewComment } from "../github-BdWWueJP.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/eve/fetch.d.ts
5
5
  /** The subset of the eve sandbox handle a credentialed git operation needs. */
@@ -362,7 +362,7 @@ declare function invokeAgentTool(stores: FactoryStores, options: InvokeAgentOpti
362
362
  }, {
363
363
  taskId: string;
364
364
  kind: string;
365
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
365
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
366
366
  }> & {
367
367
  execute(input: {
368
368
  repositoryIds: string[];
@@ -374,7 +374,7 @@ declare function invokeAgentTool(stores: FactoryStores, options: InvokeAgentOpti
374
374
  }, ctx: import("eve/tools").ToolContext): Promise<{
375
375
  taskId: string;
376
376
  kind: string;
377
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
377
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
378
378
  }>;
379
379
  };
380
380
  //#endregion
@@ -484,8 +484,8 @@ declare function recordVerificationTool(stores: FactoryStores): import("eve/tool
484
484
  } | {
485
485
  recorded: true;
486
486
  verdict: "pass" | "fail";
487
- changeState: "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "rolled_back" | "closed";
488
- taskState: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
487
+ changeState: "rolled_back" | "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "closed";
488
+ taskState: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
489
489
  reason?: undefined;
490
490
  }> & {
491
491
  execute(input: {
@@ -511,8 +511,8 @@ declare function recordVerificationTool(stores: FactoryStores): import("eve/tool
511
511
  } | {
512
512
  recorded: true;
513
513
  verdict: "pass" | "fail";
514
- changeState: "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "rolled_back" | "closed";
515
- taskState: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
514
+ changeState: "rolled_back" | "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "closed";
515
+ taskState: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
516
516
  reason?: undefined;
517
517
  }>;
518
518
  };
@@ -563,7 +563,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
563
563
  schemaVersion: 1;
564
564
  id: string;
565
565
  kind: string;
566
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
566
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
567
567
  origin: {
568
568
  signalId?: string | undefined;
569
569
  parentTaskId?: string | undefined;
@@ -605,7 +605,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
605
605
  schemaVersion: 1;
606
606
  id: string;
607
607
  kind: string;
608
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
608
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
609
609
  origin: {
610
610
  signalId?: string | undefined;
611
611
  parentTaskId?: string | undefined;
@@ -713,18 +713,19 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
713
713
  scopeMatches: boolean;
714
714
  previewUrl?: string | undefined;
715
715
  };
716
- state: "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "rolled_back" | "closed";
716
+ state: "rolled_back" | "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "closed";
717
717
  createdAt: string;
718
718
  updatedAt: string;
719
719
  taskId?: string | undefined;
720
720
  groupId?: string | undefined;
721
+ mergeSha?: string | undefined;
721
722
  decidedBy?: string | undefined;
722
723
  };
723
724
  task: {
724
725
  schemaVersion: 1;
725
726
  id: string;
726
727
  kind: string;
727
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
728
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
728
729
  origin: {
729
730
  signalId?: string | undefined;
730
731
  parentTaskId?: string | undefined;
@@ -784,18 +785,19 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
784
785
  scopeMatches: boolean;
785
786
  previewUrl?: string | undefined;
786
787
  };
787
- state: "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "rolled_back" | "closed";
788
+ state: "rolled_back" | "verifying" | "ready" | "merged" | "deployed" | "rolled_out" | "closed";
788
789
  createdAt: string;
789
790
  updatedAt: string;
790
791
  taskId?: string | undefined;
791
792
  groupId?: string | undefined;
793
+ mergeSha?: string | undefined;
792
794
  decidedBy?: string | undefined;
793
795
  };
794
796
  task: {
795
797
  schemaVersion: 1;
796
798
  id: string;
797
799
  kind: string;
798
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
800
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
799
801
  origin: {
800
802
  signalId?: string | undefined;
801
803
  parentTaskId?: string | undefined;
@@ -839,7 +841,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
839
841
  taskState?: undefined;
840
842
  } | {
841
843
  finished: true;
842
- taskState: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
844
+ taskState: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
843
845
  reason?: undefined;
844
846
  }> & {
845
847
  execute(input: {
@@ -851,7 +853,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
851
853
  taskState?: undefined;
852
854
  } | {
853
855
  finished: true;
854
- taskState: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
856
+ taskState: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
855
857
  reason?: undefined;
856
858
  }>;
857
859
  };
@@ -862,7 +864,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
862
864
  schemaVersion: 1;
863
865
  id: string;
864
866
  kind: string;
865
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
867
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
866
868
  origin: {
867
869
  signalId?: string | undefined;
868
870
  parentTaskId?: string | undefined;
@@ -902,7 +904,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
902
904
  schemaVersion: 1;
903
905
  id: string;
904
906
  kind: string;
905
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
907
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
906
908
  origin: {
907
909
  signalId?: string | undefined;
908
910
  parentTaskId?: string | undefined;
@@ -949,7 +951,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
949
951
  schemaVersion: 1;
950
952
  id: string;
951
953
  kind: string;
952
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
954
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
953
955
  origin: {
954
956
  signalId?: string | undefined;
955
957
  parentTaskId?: string | undefined;
@@ -995,7 +997,7 @@ declare function factoryTools(stores: FactoryStores, options?: FactoryToolsOptio
995
997
  schemaVersion: 1;
996
998
  id: string;
997
999
  kind: string;
998
- state: "queued" | "running" | "verifying" | "succeeded" | "failed" | "needs_human" | "cancelled";
1000
+ state: "succeeded" | "failed" | "needs_human" | "queued" | "running" | "verifying" | "cancelled";
999
1001
  origin: {
1000
1002
  signalId?: string | undefined;
1001
1003
  parentTaskId?: string | undefined;
@@ -1,5 +1,5 @@
1
1
  import { i as repositoryIdSchema, o as signalIdSchema, p as vocabularySchema, s as taskIdSchema, t as changeIdSchema } from "../id-DwCihQr4.mjs";
2
- import { S as findingFingerprint, b as requiresApproval, g as dispatchTask, p as levelSchema, s as taskQuestionSchema, u as changeEvidenceSchema, w as findingSchema, y as defaultApprovalPolicy } from "../task-Cj7Ei9Nh.mjs";
2
+ import { S as findingFingerprint, b as requiresApproval, g as dispatchTask, p as levelSchema, s as taskQuestionSchema, u as changeEvidenceSchema, w as findingSchema, y as defaultApprovalPolicy } from "../task-BxTU3MJb.mjs";
3
3
  import { answerReviewComment, readPullRequestHead, readReviewComment } from "../github.mjs";
4
4
  import { z } from "zod";
5
5
  import { defineHook } from "eve/hooks";
@@ -1,4 +1,4 @@
1
- import { a as NormalizedSignal, s as WebhookEvent } from "./index-WNGZJRRH.mjs";
1
+ import { a as NormalizedSignal, s as WebhookEvent } from "./index-DUb-U5cy.mjs";
2
2
  //#region src/github.d.ts
3
3
  interface GitHubRepositoryRequest {
4
4
  repository: string;
@@ -133,6 +133,8 @@ interface GitHubPullRequestClosed {
133
133
  prNumber: number;
134
134
  prUrl: string;
135
135
  merged: boolean;
136
+ /** The merge commit on the base branch; null when closed without merging. */
137
+ mergeCommitSha: string | null;
136
138
  /** The GitHub login that merged the pull request, or closed it without merging. */
137
139
  decidedBy: string;
138
140
  }
@@ -146,4 +148,4 @@ declare function normalizeGitHubPullRequestClosed(options: WebhookEvent): GitHub
146
148
  declare function normalizeGitHubWorkflowRunFailure(options: WebhookEvent): GitHubCIFailureSignal | null;
147
149
  //#endregion
148
150
  export { normalizeGitHubIssueOpened as C, readReviewComment as D, readPullRequestHead as E, removeLabel as O, normalizeGitHubDefaultBranchPush as S, normalizeGitHubWorkflowRunFailure as T, ReviewCommentAuthorPolicy as _, GitHubCIFailureSignal as a, createPullRequest as b, GitHubPullRequestClosed as c, GitHubReviewComment as d, GitHubReviewCommentAuthorError as f, ReadReviewCommentInput as g, ReadPullRequestHeadInput as h, CreatedPullRequest as i, verifyGitHubSignature as k, GitHubPullRequestHead as l, PullRequestLabelInput as m, ConflictedPullRequest as n, GitHubDefaultBranchPush as o, ListConflictedPullRequestsInput as p, CreatePullRequestInput as r, GitHubIssueSignal as s, AnswerReviewCommentInput as t, GitHubRepositoryRequest as u, addLabel as v, normalizeGitHubPullRequestClosed as w, listConflictedPullRequests as x, answerReviewComment as y };
149
- //# sourceMappingURL=github-3sbHe-fo.d.mts.map
151
+ //# sourceMappingURL=github-BdWWueJP.d.mts.map
package/dist/github.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { C as normalizeGitHubIssueOpened, D as readReviewComment, E as readPullRequestHead, O as removeLabel, S as normalizeGitHubDefaultBranchPush, T as normalizeGitHubWorkflowRunFailure, _ as ReviewCommentAuthorPolicy, a as GitHubCIFailureSignal, b as createPullRequest, c as GitHubPullRequestClosed, d as GitHubReviewComment, f as GitHubReviewCommentAuthorError, g as ReadReviewCommentInput, h as ReadPullRequestHeadInput, i as CreatedPullRequest, k as verifyGitHubSignature, l as GitHubPullRequestHead, m as PullRequestLabelInput, n as ConflictedPullRequest, o as GitHubDefaultBranchPush, p as ListConflictedPullRequestsInput, r as CreatePullRequestInput, s as GitHubIssueSignal, t as AnswerReviewCommentInput, u as GitHubRepositoryRequest, v as addLabel, w as normalizeGitHubPullRequestClosed, x as listConflictedPullRequests, y as answerReviewComment } from "./github-3sbHe-fo.mjs";
1
+ import { C as normalizeGitHubIssueOpened, D as readReviewComment, E as readPullRequestHead, O as removeLabel, S as normalizeGitHubDefaultBranchPush, T as normalizeGitHubWorkflowRunFailure, _ as ReviewCommentAuthorPolicy, a as GitHubCIFailureSignal, b as createPullRequest, c as GitHubPullRequestClosed, d as GitHubReviewComment, f as GitHubReviewCommentAuthorError, g as ReadReviewCommentInput, h as ReadPullRequestHeadInput, i as CreatedPullRequest, k as verifyGitHubSignature, l as GitHubPullRequestHead, m as PullRequestLabelInput, n as ConflictedPullRequest, o as GitHubDefaultBranchPush, p as ListConflictedPullRequestsInput, r as CreatePullRequestInput, s as GitHubIssueSignal, t as AnswerReviewCommentInput, u as GitHubRepositoryRequest, v as addLabel, w as normalizeGitHubPullRequestClosed, x as listConflictedPullRequests, y as answerReviewComment } from "./github-BdWWueJP.mjs";
2
2
  export { AnswerReviewCommentInput, ConflictedPullRequest, CreatePullRequestInput, CreatedPullRequest, GitHubCIFailureSignal, GitHubDefaultBranchPush, GitHubIssueSignal, GitHubPullRequestClosed, GitHubPullRequestHead, GitHubRepositoryRequest, GitHubReviewComment, GitHubReviewCommentAuthorError, ListConflictedPullRequestsInput, PullRequestLabelInput, ReadPullRequestHeadInput, ReadReviewCommentInput, ReviewCommentAuthorPolicy, addLabel, answerReviewComment, createPullRequest, listConflictedPullRequests, normalizeGitHubDefaultBranchPush, normalizeGitHubIssueOpened, normalizeGitHubPullRequestClosed, normalizeGitHubWorkflowRunFailure, readPullRequestHead, readReviewComment, removeLabel, verifyGitHubSignature };
package/dist/github.mjs CHANGED
@@ -268,7 +268,8 @@ const pullRequestClosedSchema = z.looseObject({
268
268
  number: z.number().int().min(1),
269
269
  html_url: z.url(),
270
270
  merged: z.boolean(),
271
- merged_by: z.looseObject({ login: z.string().min(1) }).nullable().optional()
271
+ merged_by: z.looseObject({ login: z.string().min(1) }).nullable().optional(),
272
+ merge_commit_sha: z.string().regex(/^[0-9a-f]{40}$/).nullable().optional()
272
273
  }),
273
274
  repository: z.looseObject({ full_name: z.string().min(1) }),
274
275
  sender: z.looseObject({ login: z.string().min(1) })
@@ -291,6 +292,7 @@ function normalizeGitHubPullRequestClosed(options) {
291
292
  prNumber: pr.number,
292
293
  prUrl: pr.html_url,
293
294
  merged: pr.merged,
295
+ mergeCommitSha: pr.merged ? pr.merge_commit_sha ?? null : null,
294
296
  decidedBy: pr.merged ? pr.merged_by?.login ?? sender : sender
295
297
  };
296
298
  }