@mastra/factory 0.17.3-alpha.3 → 0.17.3-alpha.4
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/dist/integrations/github/issue-reconciler.d.ts +5 -3
- package/dist/integrations/github/issue-reconciler.d.ts.map +1 -1
- package/dist/integrations/github/issue-reconciler.js +24 -4
- package/dist/integrations/github/issue-reconciler.js.map +1 -1
- package/dist/integrations/github/rules.d.ts +15 -0
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +14 -1
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.d.ts.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +15 -0
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts +6 -0
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +26 -1
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IntegrationContext } from '../base.js';
|
|
2
|
-
import type { GithubIssueFetcher, GithubRulesIntegration, GithubRulesOptions, ReconcileRepository } from './rules.js';
|
|
2
|
+
import type { GithubIssueFetcher, GithubOpenIssueLister, GithubRulesIntegration, GithubRulesOptions, ReconcileRepository } from './rules.js';
|
|
3
3
|
export interface GithubIssueReconcileSummary {
|
|
4
4
|
/** Repositories included in the sweep. */
|
|
5
5
|
repositories: number;
|
|
@@ -11,6 +11,8 @@ export interface GithubIssueReconcileSummary {
|
|
|
11
11
|
closed: number;
|
|
12
12
|
/** Open issues whose changed labels were replayed through the rules ingress. */
|
|
13
13
|
relabeled: number;
|
|
14
|
+
/** Open issues with no Work card replayed as `opened` through the rules ingress. */
|
|
15
|
+
created: number;
|
|
14
16
|
/** Errors encountered during the sweep. */
|
|
15
17
|
failed: number;
|
|
16
18
|
/** Error samples with context. */
|
|
@@ -21,6 +23,6 @@ export interface GithubIssueReconcileSummary {
|
|
|
21
23
|
}>;
|
|
22
24
|
}
|
|
23
25
|
export type GithubIssueReconciler = (repositories: ReconcileRepository[]) => Promise<GithubIssueReconcileSummary>;
|
|
24
|
-
export declare function createGithubIssueReconciler(options: GithubRulesOptions, fetchIssue: GithubIssueFetcher): GithubIssueReconciler;
|
|
25
|
-
export declare function attachGithubIssueReconciler(github: GithubRulesIntegration, context: IntegrationContext, fetchIssue: GithubIssueFetcher): GithubIssueReconciler | undefined;
|
|
26
|
+
export declare function createGithubIssueReconciler(options: GithubRulesOptions, fetchIssue: GithubIssueFetcher, listOpenIssues?: GithubOpenIssueLister): GithubIssueReconciler;
|
|
27
|
+
export declare function attachGithubIssueReconciler(github: GithubRulesIntegration, context: IntegrationContext, fetchIssue: GithubIssueFetcher, listOpenIssues?: GithubOpenIssueLister): GithubIssueReconciler | undefined;
|
|
26
28
|
//# sourceMappingURL=issue-reconciler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-reconciler.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/issue-reconciler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"issue-reconciler.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/issue-reconciler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAYrD,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,2BAA2B;IAC1C,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,MAAM,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5E;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,YAAY,EAAE,mBAAmB,EAAE,KAAK,OAAO,CAAC,2BAA2B,CAAC,CAAC;AAElH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,kBAAkB,EAC9B,cAAc,CAAC,EAAE,qBAAqB,GACrC,qBAAqB,CAyKvB;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,kBAAkB,EAC9B,cAAc,CAAC,EAAE,qBAAqB,GACrC,qBAAqB,GAAG,SAAS,CAKnC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { workItemPhaseSemantics } from "../../boards/semantics.js";
|
|
2
2
|
import "../../boards/index.js";
|
|
3
|
-
import { GithubRules, githubRulesOptions, reconcilableIssueNumber, reconciledIssueClosedEvent, reconciledIssueRelabeledEvent, sameStrings, sweepTrustLookup } from "./rules.js";
|
|
3
|
+
import { GithubRules, githubRulesOptions, reconcilableIssueNumber, reconciledIssueClosedEvent, reconciledIssueOpenedEvent, reconciledIssueRelabeledEvent, sameStrings, sweepTrustLookup } from "./rules.js";
|
|
4
4
|
//#region src/integrations/github/issue-reconciler.ts
|
|
5
|
-
function createGithubIssueReconciler(options, fetchIssue) {
|
|
5
|
+
function createGithubIssueReconciler(options, fetchIssue, listOpenIssues) {
|
|
6
6
|
const rules = new GithubRules(options);
|
|
7
7
|
return async (repositories) => {
|
|
8
8
|
const summary = {
|
|
@@ -11,6 +11,7 @@ function createGithubIssueReconciler(options, fetchIssue) {
|
|
|
11
11
|
updated: 0,
|
|
12
12
|
closed: 0,
|
|
13
13
|
relabeled: 0,
|
|
14
|
+
created: 0,
|
|
14
15
|
failed: 0,
|
|
15
16
|
errors: []
|
|
16
17
|
};
|
|
@@ -32,6 +33,7 @@ function createGithubIssueReconciler(options, fetchIssue) {
|
|
|
32
33
|
});
|
|
33
34
|
if (projects.length === 0) continue;
|
|
34
35
|
const itemsByNumber = /* @__PURE__ */ new Map();
|
|
36
|
+
const carded = /* @__PURE__ */ new Set();
|
|
35
37
|
for (const project of projects) {
|
|
36
38
|
const items = await options.storage.list({
|
|
37
39
|
orgId: project.orgId,
|
|
@@ -40,6 +42,7 @@ function createGithubIssueReconciler(options, fetchIssue) {
|
|
|
40
42
|
for (const item of items) {
|
|
41
43
|
const issueNumber = reconcilableIssueNumber(item, repository);
|
|
42
44
|
if (!issueNumber) continue;
|
|
45
|
+
carded.add(issueNumber);
|
|
43
46
|
if (workItemPhaseSemantics(options.boards, item)?.kind === "terminal") continue;
|
|
44
47
|
let list = itemsByNumber.get(issueNumber);
|
|
45
48
|
if (!list) {
|
|
@@ -49,6 +52,23 @@ function createGithubIssueReconciler(options, fetchIssue) {
|
|
|
49
52
|
list.push(item);
|
|
50
53
|
}
|
|
51
54
|
}
|
|
55
|
+
if (listOpenIssues) {
|
|
56
|
+
const linkedAt = Math.min(...projects.map((project) => project.projectRepository.createdAt.getTime()));
|
|
57
|
+
const openIssues = await listOpenIssues({
|
|
58
|
+
installationId: repository.installationId,
|
|
59
|
+
repository: repository.fullName
|
|
60
|
+
});
|
|
61
|
+
for (const issue of openIssues) {
|
|
62
|
+
if (carded.has(issue.number)) continue;
|
|
63
|
+
const createdAt = issue.createdAt ? Date.parse(issue.createdAt) : NaN;
|
|
64
|
+
if (!Number.isFinite(createdAt) || createdAt < linkedAt) continue;
|
|
65
|
+
try {
|
|
66
|
+
if ((await rules.ingest(reconciledIssueOpenedEvent(repository, issue.number, issue))).status === "committed") summary.created += 1;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
recordFailure(repository, error, issue.number);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
52
72
|
for (const [issueNumber, items] of itemsByNumber) try {
|
|
53
73
|
const state = await fetchIssue({
|
|
54
74
|
installationId: repository.installationId,
|
|
@@ -106,11 +126,11 @@ function createGithubIssueReconciler(options, fetchIssue) {
|
|
|
106
126
|
return summary;
|
|
107
127
|
};
|
|
108
128
|
}
|
|
109
|
-
function attachGithubIssueReconciler(github, context, fetchIssue) {
|
|
129
|
+
function attachGithubIssueReconciler(github, context, fetchIssue, listOpenIssues) {
|
|
110
130
|
if (!context.runtime) return void 0;
|
|
111
131
|
const options = githubRulesOptions(github, context);
|
|
112
132
|
if (!options) return void 0;
|
|
113
|
-
return createGithubIssueReconciler(options, fetchIssue);
|
|
133
|
+
return createGithubIssueReconciler(options, fetchIssue, listOpenIssues);
|
|
114
134
|
}
|
|
115
135
|
//#endregion
|
|
116
136
|
export { attachGithubIssueReconciler, createGithubIssueReconciler };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-reconciler.js","names":[],"sources":["../../../src/integrations/github/issue-reconciler.ts"],"sourcesContent":["import { workItemPhaseSemantics } from '../../boards/index.js';\nimport type { IntegrationContext } from '../base.js';\nimport {\n githubRulesOptions,\n reconcilableIssueNumber,\n reconciledIssueClosedEvent,\n reconciledIssueRelabeledEvent,\n RECONCILE_ERROR_SAMPLE_LIMIT,\n sameStrings,\n sweepTrustLookup,\n GithubRules,\n} from './rules.js';\nimport type { GithubIssueFetcher, GithubRulesIntegration, GithubRulesOptions, ReconcileRepository } from './rules.js';\n\nexport interface GithubIssueReconcileSummary {\n /** Repositories included in the sweep. */\n repositories: number;\n /** Issue cards whose live state was fetched. */\n checked: number;\n /** Open issues with metadata patches. */\n updated: number;\n /** Closed issues replayed through the rules ingress. */\n closed: number;\n /** Open issues whose changed labels were replayed through the rules ingress. */\n relabeled: number;\n /** Errors encountered during the sweep. */\n failed: number;\n /** Error samples with context. */\n errors: Array<{ repository: string; issueNumber?: number; error: string }>;\n}\n\nexport type GithubIssueReconciler = (repositories: ReconcileRepository[]) => Promise<GithubIssueReconcileSummary>;\n\nexport function createGithubIssueReconciler(\n options: GithubRulesOptions,\n fetchIssue: GithubIssueFetcher,\n): GithubIssueReconciler {\n const rules = new GithubRules(options);\n return async repositories => {\n const summary: GithubIssueReconcileSummary = {\n repositories: 0,\n checked: 0,\n updated: 0,\n closed: 0,\n relabeled: 0,\n failed: 0,\n errors: [],\n };\n const recordFailure = (repository: ReconcileRepository, error: unknown, issueNumber?: number) => {\n summary.failed += 1;\n if (summary.errors.length < RECONCILE_ERROR_SAMPLE_LIMIT) {\n summary.errors.push({\n repository: repository.fullName,\n ...(issueNumber === undefined ? {} : { issueNumber }),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n };\n\n for (const repository of repositories) {\n summary.repositories += 1;\n const authorTrust = sweepTrustLookup(options.github, repository);\n\n try {\n const projects = await options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n });\n if (projects.length === 0) continue;\n\n // Collect issue cards: number -> items (skip terminal stages)\n const itemsByNumber = new Map<number, import('../../storage/domains/work-items/base.js').WorkItemRow[]>();\n\n for (const project of projects) {\n const items = await options.storage.list({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n });\n for (const item of items) {\n const issueNumber = reconcilableIssueNumber(item, repository);\n if (!issueNumber) continue;\n if (workItemPhaseSemantics(options.boards, item)?.kind === 'terminal') continue;\n let list = itemsByNumber.get(issueNumber);\n if (!list) {\n list = [];\n itemsByNumber.set(issueNumber, list);\n }\n list.push(item);\n }\n }\n\n // Fetch and reconcile each unique issue\n for (const [issueNumber, items] of itemsByNumber) {\n try {\n const state = await fetchIssue({\n installationId: repository.installationId,\n repository: repository.fullName,\n number: issueNumber,\n });\n if (!state) continue; // missing or PR-backed\n summary.checked += 1;\n\n // Close detection: replay through rules ingress\n if (state.state === 'closed') {\n await rules.ingest(reconciledIssueClosedEvent(repository, issueNumber, state));\n summary.closed += 1;\n continue; // card transitions, skip metadata patch\n }\n\n // Metadata sync for open issues\n const desiredMetadata = {\n githubRepositoryId: repository.id,\n githubIssueNumber: issueNumber,\n state: 'open' as const,\n ...(state.author === undefined ? {} : { author: state.author }),\n ...(state.assignees === undefined ? {} : { assignees: state.assignees }),\n ...(state.labels === undefined ? {} : { labels: state.labels }),\n };\n // Re-stamped on every sweep so revoked write access reads untrusted\n // within one cycle; a failed lookup keeps the last stamp and retries.\n let authorTrusted: boolean | undefined;\n if (state.author !== undefined) {\n try {\n authorTrusted = await authorTrust(state.author);\n } catch (error) {\n recordFailure(repository, error, issueNumber);\n }\n }\n\n // Label drift decides where the card belongs, and the rule that owns\n // that decision has to run again — mirrored from the `labeled` /\n // `unlabeled` webhook, replayed here so a label Factory never saw a\n // delivery for still re-places the card. Replayed before the\n // metadata patch, so the ingress sees the drift it acts on.\n if (\n state.labels !== undefined &&\n items.some(item => Array.isArray(item.metadata?.labels) && !sameStrings(item.metadata.labels, state.labels))\n ) {\n await rules.ingest(reconciledIssueRelabeledEvent(repository, issueNumber, state));\n summary.relabeled += 1;\n }\n\n for (const item of items) {\n const current = item.metadata ?? {};\n const trustStale = authorTrusted !== undefined && current.authorTrusted !== authorTrusted;\n const metadataChanged =\n trustStale ||\n current.githubRepositoryId !== desiredMetadata.githubRepositoryId ||\n current.githubIssueNumber !== desiredMetadata.githubIssueNumber ||\n current.state !== desiredMetadata.state ||\n (state.author !== undefined && current.author !== state.author) ||\n (state.assignees !== undefined && !sameStrings(current.assignees, state.assignees)) ||\n (state.labels !== undefined && !sameStrings(current.labels, state.labels));\n\n if (!metadataChanged) continue;\n\n await options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { ...current, ...desiredMetadata, ...(trustStale ? { authorTrusted } : {}) } },\n });\n summary.updated += 1;\n }\n } catch (error) {\n recordFailure(repository, error, issueNumber);\n }\n }\n } catch (error) {\n recordFailure(repository, error);\n }\n }\n\n return summary;\n };\n}\n\nexport function attachGithubIssueReconciler(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n fetchIssue: GithubIssueFetcher,\n): GithubIssueReconciler | undefined {\n if (!context.runtime) return undefined;\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n return createGithubIssueReconciler(options, fetchIssue);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"issue-reconciler.js","names":[],"sources":["../../../src/integrations/github/issue-reconciler.ts"],"sourcesContent":["import { workItemPhaseSemantics } from '../../boards/index.js';\nimport type { IntegrationContext } from '../base.js';\nimport {\n githubRulesOptions,\n reconcilableIssueNumber,\n reconciledIssueClosedEvent,\n reconciledIssueOpenedEvent,\n reconciledIssueRelabeledEvent,\n RECONCILE_ERROR_SAMPLE_LIMIT,\n sameStrings,\n sweepTrustLookup,\n GithubRules,\n} from './rules.js';\nimport type {\n GithubIssueFetcher,\n GithubOpenIssueLister,\n GithubRulesIntegration,\n GithubRulesOptions,\n ReconcileRepository,\n} from './rules.js';\n\nexport interface GithubIssueReconcileSummary {\n /** Repositories included in the sweep. */\n repositories: number;\n /** Issue cards whose live state was fetched. */\n checked: number;\n /** Open issues with metadata patches. */\n updated: number;\n /** Closed issues replayed through the rules ingress. */\n closed: number;\n /** Open issues whose changed labels were replayed through the rules ingress. */\n relabeled: number;\n /** Open issues with no Work card replayed as `opened` through the rules ingress. */\n created: number;\n /** Errors encountered during the sweep. */\n failed: number;\n /** Error samples with context. */\n errors: Array<{ repository: string; issueNumber?: number; error: string }>;\n}\n\nexport type GithubIssueReconciler = (repositories: ReconcileRepository[]) => Promise<GithubIssueReconcileSummary>;\n\nexport function createGithubIssueReconciler(\n options: GithubRulesOptions,\n fetchIssue: GithubIssueFetcher,\n listOpenIssues?: GithubOpenIssueLister,\n): GithubIssueReconciler {\n const rules = new GithubRules(options);\n return async repositories => {\n const summary: GithubIssueReconcileSummary = {\n repositories: 0,\n checked: 0,\n updated: 0,\n closed: 0,\n relabeled: 0,\n created: 0,\n failed: 0,\n errors: [],\n };\n const recordFailure = (repository: ReconcileRepository, error: unknown, issueNumber?: number) => {\n summary.failed += 1;\n if (summary.errors.length < RECONCILE_ERROR_SAMPLE_LIMIT) {\n summary.errors.push({\n repository: repository.fullName,\n ...(issueNumber === undefined ? {} : { issueNumber }),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n };\n\n for (const repository of repositories) {\n summary.repositories += 1;\n const authorTrust = sweepTrustLookup(options.github, repository);\n\n try {\n const projects = await options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n });\n if (projects.length === 0) continue;\n\n // Collect issue cards: number -> items (skip terminal stages)\n const itemsByNumber = new Map<number, import('../../storage/domains/work-items/base.js').WorkItemRow[]>();\n // Every issue with any card, terminal included: a finished card must\n // not be re-minted by missed-open discovery.\n const carded = new Set<number>();\n\n for (const project of projects) {\n const items = await options.storage.list({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n });\n for (const item of items) {\n const issueNumber = reconcilableIssueNumber(item, repository);\n if (!issueNumber) continue;\n carded.add(issueNumber);\n if (workItemPhaseSemantics(options.boards, item)?.kind === 'terminal') continue;\n let list = itemsByNumber.get(issueNumber);\n if (!list) {\n list = [];\n itemsByNumber.set(issueNumber, list);\n }\n list.push(item);\n }\n }\n\n // Missed-open discovery: an `opened` delivery that never reached the\n // ingress leaves no card for the sweeps above to repair. Only issues\n // filed after the repository was linked are replayed, so linking a\n // repository never backfills its existing backlog.\n if (listOpenIssues) {\n const linkedAt = Math.min(...projects.map(project => project.projectRepository.createdAt.getTime()));\n const openIssues = await listOpenIssues({\n installationId: repository.installationId,\n repository: repository.fullName,\n });\n for (const issue of openIssues) {\n if (carded.has(issue.number)) continue;\n const createdAt = issue.createdAt ? Date.parse(issue.createdAt) : Number.NaN;\n if (!Number.isFinite(createdAt) || createdAt < linkedAt) continue;\n try {\n const result = await rules.ingest(reconciledIssueOpenedEvent(repository, issue.number, issue));\n if (result.status === 'committed') summary.created += 1;\n } catch (error) {\n recordFailure(repository, error, issue.number);\n }\n }\n }\n\n // Fetch and reconcile each unique issue\n for (const [issueNumber, items] of itemsByNumber) {\n try {\n const state = await fetchIssue({\n installationId: repository.installationId,\n repository: repository.fullName,\n number: issueNumber,\n });\n if (!state) continue; // missing or PR-backed\n summary.checked += 1;\n\n // Close detection: replay through rules ingress\n if (state.state === 'closed') {\n await rules.ingest(reconciledIssueClosedEvent(repository, issueNumber, state));\n summary.closed += 1;\n continue; // card transitions, skip metadata patch\n }\n\n // Metadata sync for open issues\n const desiredMetadata = {\n githubRepositoryId: repository.id,\n githubIssueNumber: issueNumber,\n state: 'open' as const,\n ...(state.author === undefined ? {} : { author: state.author }),\n ...(state.assignees === undefined ? {} : { assignees: state.assignees }),\n ...(state.labels === undefined ? {} : { labels: state.labels }),\n };\n // Re-stamped on every sweep so revoked write access reads untrusted\n // within one cycle; a failed lookup keeps the last stamp and retries.\n let authorTrusted: boolean | undefined;\n if (state.author !== undefined) {\n try {\n authorTrusted = await authorTrust(state.author);\n } catch (error) {\n recordFailure(repository, error, issueNumber);\n }\n }\n\n // Label drift decides where the card belongs, and the rule that owns\n // that decision has to run again — mirrored from the `labeled` /\n // `unlabeled` webhook, replayed here so a label Factory never saw a\n // delivery for still re-places the card. Replayed before the\n // metadata patch, so the ingress sees the drift it acts on.\n if (\n state.labels !== undefined &&\n items.some(\n item => Array.isArray(item.metadata?.labels) && !sameStrings(item.metadata.labels, state.labels),\n )\n ) {\n await rules.ingest(reconciledIssueRelabeledEvent(repository, issueNumber, state));\n summary.relabeled += 1;\n }\n\n for (const item of items) {\n const current = item.metadata ?? {};\n const trustStale = authorTrusted !== undefined && current.authorTrusted !== authorTrusted;\n const metadataChanged =\n trustStale ||\n current.githubRepositoryId !== desiredMetadata.githubRepositoryId ||\n current.githubIssueNumber !== desiredMetadata.githubIssueNumber ||\n current.state !== desiredMetadata.state ||\n (state.author !== undefined && current.author !== state.author) ||\n (state.assignees !== undefined && !sameStrings(current.assignees, state.assignees)) ||\n (state.labels !== undefined && !sameStrings(current.labels, state.labels));\n\n if (!metadataChanged) continue;\n\n await options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { ...current, ...desiredMetadata, ...(trustStale ? { authorTrusted } : {}) } },\n });\n summary.updated += 1;\n }\n } catch (error) {\n recordFailure(repository, error, issueNumber);\n }\n }\n } catch (error) {\n recordFailure(repository, error);\n }\n }\n\n return summary;\n };\n}\n\nexport function attachGithubIssueReconciler(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n fetchIssue: GithubIssueFetcher,\n listOpenIssues?: GithubOpenIssueLister,\n): GithubIssueReconciler | undefined {\n if (!context.runtime) return undefined;\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n return createGithubIssueReconciler(options, fetchIssue, listOpenIssues);\n}\n"],"mappings":"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"}
|
|
@@ -84,6 +84,13 @@ export type GithubIssueFetcher = (input: {
|
|
|
84
84
|
repository: string;
|
|
85
85
|
number: number;
|
|
86
86
|
}) => Promise<ReconcileIssueState | undefined>;
|
|
87
|
+
/** Lists a repository's open issues (pull requests excluded) for missed-open discovery. */
|
|
88
|
+
export type GithubOpenIssueLister = (input: {
|
|
89
|
+
installationId: number;
|
|
90
|
+
repository: string;
|
|
91
|
+
}) => Promise<Array<ReconcileIssueState & {
|
|
92
|
+
number: number;
|
|
93
|
+
}>>;
|
|
87
94
|
export interface ReconcileRepository {
|
|
88
95
|
id: number;
|
|
89
96
|
fullName: string;
|
|
@@ -129,6 +136,14 @@ export declare function reconciledIssueClosedEvent(repository: ReconcileReposito
|
|
|
129
136
|
* source of placement policy for both.
|
|
130
137
|
*/
|
|
131
138
|
export declare function reconciledIssueRelabeledEvent(repository: ReconcileRepository, issueNumber: number, state: ReconcileIssueState): ParsedGithubWebhook;
|
|
139
|
+
/**
|
|
140
|
+
* The missed-open replay: an open issue with no Work card, because its
|
|
141
|
+
* `opened` delivery never reached the rules ingress. Synthesized as the same
|
|
142
|
+
* `opened` delivery so the deployment's `issueOpened` rule decides whether and
|
|
143
|
+
* where it lands, exactly as it would have at arrival. The delivery id is
|
|
144
|
+
* stable per issue so repeat sweeps dedupe at the ingress.
|
|
145
|
+
*/
|
|
146
|
+
export declare function reconciledIssueOpenedEvent(repository: ReconcileRepository, issueNumber: number, state: ReconcileIssueState): ParsedGithubWebhook;
|
|
132
147
|
export declare function reconciledClosedEvent(repository: ReconcileRepository, pullRequestNumber: number, state: ReconcilePullRequestState): ParsedGithubWebhook;
|
|
133
148
|
/**
|
|
134
149
|
* State-based safety net for merge signals: webhooks and event-log tailing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/rules.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/rules.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAU3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AAC1E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAC3F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,KAAK,EAEV,0BAA0B,EAC3B,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAK9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAmJxD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,sBAAsB,EAC9B,KAAK,EAAE;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnE,OAAO,CAAC,OAAO,CAAC,CAOlB;AAiBD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,UAAU,EAAE,mBAAmB,GAC9B,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAarC;AA+BD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,mCAAmC,CACjC,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,aAAa,EAAE,0BAA0B,CAAC;IAC1C,yEAAyE;IACzE,kBAAkB,EAAE,wBAAwB,CAAC;IAC7C,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,aAAa,CAAC;IACtB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,iBAAiB,CAAC,CAAC;CACjD;AAUD,qBAAa,WAAW;;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAkGlD,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;KAAE,CAAC;CA0bjH;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC;AAE/C,2FAA2F;AAC3F,MAAM,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,KAAK,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,MAAM,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxG;AAED,MAAM,MAAM,2BAA2B,GAAG,CAAC,YAAY,EAAE,mBAAmB,EAAE,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAElH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,OAAO,CAM/E;AAyBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAoB9G;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,mBAAmB,GACzB,mBAAmB,CAuBrB;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,mBAAmB,EAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,mBAAmB,GACzB,mBAAmB,CAiCrB;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,mBAAmB,GACzB,mBAAmB,CAGrB;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,mBAAmB,EAC/B,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,yBAAyB,GAC/B,mBAAmB,CA2BrB;AAkDD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,kBAAkB,EAC3B,gBAAgB,EAAE,wBAAwB,GACzC,2BAA2B,CAiL7B;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,GAAG,SAAS,CAYhC;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,CAAC,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CAKhE;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,EAC3B,gBAAgB,EAAE,wBAAwB,GACzC,2BAA2B,GAAG,SAAS,CAIzC"}
|
|
@@ -584,6 +584,19 @@ function reconciledIssueRelabeledEvent(repository, issueNumber, state) {
|
|
|
584
584
|
}
|
|
585
585
|
};
|
|
586
586
|
}
|
|
587
|
+
/**
|
|
588
|
+
* The missed-open replay: an open issue with no Work card, because its
|
|
589
|
+
* `opened` delivery never reached the rules ingress. Synthesized as the same
|
|
590
|
+
* `opened` delivery so the deployment's `issueOpened` rule decides whether and
|
|
591
|
+
* where it lands, exactly as it would have at arrival. The delivery id is
|
|
592
|
+
* stable per issue so repeat sweeps dedupe at the ingress.
|
|
593
|
+
*/
|
|
594
|
+
function reconciledIssueOpenedEvent(repository, issueNumber, state) {
|
|
595
|
+
return {
|
|
596
|
+
...reconciledIssueRelabeledEvent(repository, issueNumber, state),
|
|
597
|
+
deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:opened`
|
|
598
|
+
};
|
|
599
|
+
}
|
|
587
600
|
function reconciledClosedEvent(repository, pullRequestNumber, state) {
|
|
588
601
|
return {
|
|
589
602
|
event: "pull_request",
|
|
@@ -823,6 +836,6 @@ function attachGithubReconciler(github, context, fetchPullRequest) {
|
|
|
823
836
|
return createGithubPullRequestReconciler(options, fetchPullRequest);
|
|
824
837
|
}
|
|
825
838
|
//#endregion
|
|
826
|
-
export { GithubRules, RECONCILE_ERROR_SAMPLE_LIMIT, attachGithubReconciler, attachGithubRules, createGithubPullRequestReconciler, githubRulesOptions, reconcilableIssueNumber, reconciledClosedEvent, reconciledIssueClosedEvent, reconciledIssueRelabeledEvent, sameStrings, sweepTrustLookup, trustedCollaborator };
|
|
839
|
+
export { GithubRules, RECONCILE_ERROR_SAMPLE_LIMIT, attachGithubReconciler, attachGithubRules, createGithubPullRequestReconciler, githubRulesOptions, reconcilableIssueNumber, reconciledClosedEvent, reconciledIssueClosedEvent, reconciledIssueOpenedEvent, reconciledIssueRelabeledEvent, sameStrings, sweepTrustLookup, trustedCollaborator };
|
|
827
840
|
|
|
828
841
|
//# sourceMappingURL=rules.js.map
|