@mastra/factory 0.10.0-alpha.2 → 0.10.0-alpha.7
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/CHANGELOG.md +80 -0
- package/dist/factory.js +2 -2
- package/dist/integrations/github/rules.d.ts.map +1 -1
- package/dist/integrations/github/rules.js +193 -127
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/routes/attention.d.ts +17 -0
- package/dist/routes/attention.d.ts.map +1 -0
- package/dist/routes/attention.js +305 -0
- package/dist/routes/attention.js.map +1 -0
- package/dist/routes/surface.d.ts +2 -3
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +60 -43
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +34 -13
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/dispatch-errors.d.ts +13 -0
- package/dist/rules/dispatch-errors.d.ts.map +1 -0
- package/dist/rules/dispatch-errors.js +77 -0
- package/dist/rules/dispatch-errors.js.map +1 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +60 -35
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +30 -14
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/terminal-cleanup.d.ts +1 -1
- package/dist/rules/terminal-cleanup.d.ts.map +1 -1
- package/dist/rules/terminal-cleanup.js +2 -2
- package/dist/rules/terminal-cleanup.js.map +1 -1
- package/dist/rules/transition-service.d.ts +2 -1
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +1 -1
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +2 -0
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +9 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/session/factory-session.d.ts +4 -0
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +10 -2
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/first-exec-capture.d.ts +16 -10
- package/dist/session/first-exec-capture.d.ts.map +1 -1
- package/dist/session/first-exec-capture.js +74 -14
- package/dist/session/first-exec-capture.js.map +1 -1
- package/dist/session/first-message-capture.d.ts +14 -10
- package/dist/session/first-message-capture.d.ts.map +1 -1
- package/dist/session/first-message-capture.js +17 -11
- package/dist/session/first-message-capture.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +3 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +8 -2
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +101 -10
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +458 -35
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/work-item-branch.d.ts +23 -0
- package/dist/work-item-branch.d.ts.map +1 -0
- package/dist/work-item-branch.js +39 -0
- package/dist/work-item-branch.js.map +1 -0
- package/factory-skills/factory-rereview/SKILL.md +2 -0
- package/factory-skills/factory-review/SKILL.md +2 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,85 @@
|
|
|
1
1
|
# @mastra/factory
|
|
2
2
|
|
|
3
|
+
## 0.10.0-alpha.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Factory pull request review reports now show their selected model and reasoning setting: ([#22238](https://github.com/mastra-ai/mastra/pull/22238))
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
Review runtime: openai/gpt-5.6-sol, reasoning setting: high.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- Fixed retried Factory skill runs so they deliver a fresh kickoff after execution errors while preserving duplicate protection during lease recovery. ([#21926](https://github.com/mastra-ai/mastra/pull/21926))
|
|
14
|
+
|
|
15
|
+
- Fixed session timing measurements that started too early or missed workspace tool activity. ([#22213](https://github.com/mastra-ai/mastra/pull/22213))
|
|
16
|
+
|
|
17
|
+
**First interaction time**
|
|
18
|
+
Starts on the first user or assistant message. Signal-only messages (skill loads, phase markers, memory reminders) and sessions that fail before a message no longer affect this metric.
|
|
19
|
+
|
|
20
|
+
**First meaningful tool time**
|
|
21
|
+
Starts when the first workspace tool completes successfully. File operations and workspace searches count even when no shell command runs. Approval-denied and abort-while-parked tool completions are excluded because the tool never actually ran.
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [[`ae8790c`](https://github.com/mastra-ai/mastra/commit/ae8790c4bfaa088d2ab279d1dcc06f326b9fd109), [`04a815f`](https://github.com/mastra-ai/mastra/commit/04a815fc8971d29e97fcdcc5008a1eb472fc00ff), [`04a815f`](https://github.com/mastra-ai/mastra/commit/04a815fc8971d29e97fcdcc5008a1eb472fc00ff), [`cced745`](https://github.com/mastra-ai/mastra/commit/cced745a056ec2225c5bc702e32d848847aa8b65)]:
|
|
24
|
+
- @mastra/core@1.62.0-alpha.7
|
|
25
|
+
- @mastra/code-sdk@1.5.0-alpha.7
|
|
26
|
+
|
|
27
|
+
## 0.10.0-alpha.6
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [[`c8e4cea`](https://github.com/mastra-ai/mastra/commit/c8e4ceac9a390d78c8327dff3cdb2861dd71957f), [`ed01e9a`](https://github.com/mastra-ai/mastra/commit/ed01e9a807514a904374bf687a7b8f18750f6f78), [`4e9a228`](https://github.com/mastra-ai/mastra/commit/4e9a2283d5fd6ed1b70a2751eb3dc2cbf82ada20), [`63041eb`](https://github.com/mastra-ai/mastra/commit/63041eb4c50b520a0a80e03d4cd6ea99f67715a0)]:
|
|
32
|
+
- @mastra/core@1.62.0-alpha.6
|
|
33
|
+
- @mastra/code-sdk@1.5.0-alpha.6
|
|
34
|
+
|
|
35
|
+
## 0.10.0-alpha.5
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Fixed automated runs for manually created board cards. Moving a manual card into Planning or Building no longer fails with 'Factory skill invocation requires a supported issue or pull request identifier'. Manual cards now start on a stable `factory/item-<id>` branch, even without a provider identity. ([#22114](https://github.com/mastra-ai/mastra/pull/22114))
|
|
40
|
+
|
|
41
|
+
- Updated dependencies [[`65edab1`](https://github.com/mastra-ai/mastra/commit/65edab1c233d17b8f163bad12fca410d0e6f16b1), [`ab20a38`](https://github.com/mastra-ai/mastra/commit/ab20a38d0275f8d85e0f3833bd87ef487bcc609f), [`dbbfeb8`](https://github.com/mastra-ai/mastra/commit/dbbfeb85ec949dc9ebc0755e1ad262e4f5eba8db), [`3cc9d00`](https://github.com/mastra-ai/mastra/commit/3cc9d00b2b4333e0377a5e9df5eff92c17ce7630), [`733a537`](https://github.com/mastra-ai/mastra/commit/733a537489a858b5880b2e98809334fba895a221), [`9207dfa`](https://github.com/mastra-ai/mastra/commit/9207dfab8062e5fc68b751684797ff86fe0b4e70), [`12c61d2`](https://github.com/mastra-ai/mastra/commit/12c61d280c8cb208bc3c8dbcbe5dcc60cf9d1cd0), [`9a12ef3`](https://github.com/mastra-ai/mastra/commit/9a12ef3fccf3f4186db0f294f4ee1f02cf4d8db2)]:
|
|
42
|
+
- @mastra/core@1.62.0-alpha.5
|
|
43
|
+
- @mastra/code-sdk@1.5.0-alpha.5
|
|
44
|
+
|
|
45
|
+
## 0.10.0-alpha.4
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- Updated dependencies [[`79f04a7`](https://github.com/mastra-ai/mastra/commit/79f04a7f6c6829da541139f638f2f1d267916e08), [`fd4d5fe`](https://github.com/mastra-ai/mastra/commit/fd4d5fe4f943699b85db5e74404f190d5a6b8c2a), [`f591643`](https://github.com/mastra-ai/mastra/commit/f591643becdf0be9bddce6ba1748e64bc30d77f1), [`b1ad324`](https://github.com/mastra-ai/mastra/commit/b1ad324d657f3544b0701332aef7eb10e9a36258), [`61c566d`](https://github.com/mastra-ai/mastra/commit/61c566dd2f2cde2b23ed8f139924e530d4202214)]:
|
|
50
|
+
- @mastra/core@1.62.0-alpha.4
|
|
51
|
+
- @mastra/code-sdk@1.5.0-alpha.4
|
|
52
|
+
|
|
53
|
+
## 0.10.0-alpha.3
|
|
54
|
+
|
|
55
|
+
### Minor Changes
|
|
56
|
+
|
|
57
|
+
- Added a durable Factory action center for unresolved automation failures and proposed work waiting for approval. Per-user read/archive receipts survive reloads, while retries and canonical reconciliation resolve failures for every project member. ([#22021](https://github.com/mastra-ai/mastra/pull/22021))
|
|
58
|
+
|
|
59
|
+
Historical decision state is repaired on startup: accepted transitions become `succeeded`, obsolete terminal work and proposals become `superseded`, and active unresolved failures remain `failed`. Retry is offered only when the persisted failure code allows it.
|
|
60
|
+
|
|
61
|
+
**Before**
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// Failed automation and proposed runs were visible only on their board cards.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**After**
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const attention = await fetch(`/web/factory/projects/${factoryId}/attention`).then(response => response.json());
|
|
71
|
+
// attention.items: per-user unresolved failures
|
|
72
|
+
// attention.approvalCount: project-wide proposed work
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Patch Changes
|
|
76
|
+
|
|
77
|
+
- Fixed merged pull requests only reaching one of the two Factory cards that track them. A merge now both moves the Review card to Done and asks the work item that opened the pull request to assess whether its work is finished, no matter which card the merge event resolved to. ([#22135](https://github.com/mastra-ai/mastra/pull/22135))
|
|
78
|
+
|
|
79
|
+
- Updated dependencies [[`2c85f42`](https://github.com/mastra-ai/mastra/commit/2c85f428e04ccd63ea31a7ec80b5b327afdad555), [`11bbeb9`](https://github.com/mastra-ai/mastra/commit/11bbeb9b108ef2264e05acefc6dafb9cbb342921), [`1a485f3`](https://github.com/mastra-ai/mastra/commit/1a485f3538f5ec64d58bd8b5e1e99de0c695c87b), [`0d37487`](https://github.com/mastra-ai/mastra/commit/0d37487d9f349388a3f1cef6a536cf9dcc4b6273), [`8661d7d`](https://github.com/mastra-ai/mastra/commit/8661d7d7179f0a024456aabdd8679bcecd09ac28), [`575e343`](https://github.com/mastra-ai/mastra/commit/575e343900451021d96110916497d334af7bc252), [`cacb839`](https://github.com/mastra-ai/mastra/commit/cacb8392d9e74189b56d857290b0615f98a2683d), [`b47b26e`](https://github.com/mastra-ai/mastra/commit/b47b26e6fe95cb8a3482be2c5e52de157fe59d0b), [`0d37487`](https://github.com/mastra-ai/mastra/commit/0d37487d9f349388a3f1cef6a536cf9dcc4b6273), [`c46eb09`](https://github.com/mastra-ai/mastra/commit/c46eb09ce4987509af57a0ac582c61241a6dd2f1), [`30ed33e`](https://github.com/mastra-ai/mastra/commit/30ed33ee14084a26019aba15fceadda6d6ddefaf), [`91ad69d`](https://github.com/mastra-ai/mastra/commit/91ad69d64994c89199b0c55399e64ed91c61df2f), [`8dc408d`](https://github.com/mastra-ai/mastra/commit/8dc408d34438f9e13297f792c11a5cfd6cf952e1), [`c92def1`](https://github.com/mastra-ai/mastra/commit/c92def10a13c822972c96f0a4ca6ffc1f4258aed), [`c5eaec5`](https://github.com/mastra-ai/mastra/commit/c5eaec5a860d80d0e3805e67db0414b87ac8cbed), [`e66b2ba`](https://github.com/mastra-ai/mastra/commit/e66b2ba100db63eaeab6e21e1ea34b113f2ec781)]:
|
|
80
|
+
- @mastra/core@1.62.0-alpha.3
|
|
81
|
+
- @mastra/code-sdk@1.5.0-alpha.3
|
|
82
|
+
|
|
3
83
|
## 0.10.0-alpha.2
|
|
4
84
|
|
|
5
85
|
### Patch Changes
|
package/dist/factory.js
CHANGED
|
@@ -5,6 +5,7 @@ import { SandboxFleet } from "./sandbox/fleet.js";
|
|
|
5
5
|
import { BaseCheckpointBuilder } from "./sandbox/base-checkpoint.js";
|
|
6
6
|
import { createBaseCheckpointTriggers } from "./sandbox/base-checkpoint-triggers.js";
|
|
7
7
|
import { assertFactoryRules } from "./rules/validation.js";
|
|
8
|
+
import { WorkItemsStorage } from "./storage/domains/work-items/base.js";
|
|
8
9
|
import { PlatformGithubIntegration } from "./integrations/platform/github/integration.js";
|
|
9
10
|
import { PlatformLinearIntegration } from "./integrations/platform/linear/integration.js";
|
|
10
11
|
import { createCustomProvidersPrimer, registerCustomProvidersSource } from "./routes/custom-provider-source.js";
|
|
@@ -12,13 +13,13 @@ import { ProjectRoutes } from "./routes/projects.js";
|
|
|
12
13
|
import { MemorySettingsStorage } from "./storage/domains/memory-settings/base.js";
|
|
13
14
|
import { hydrateSessionMemorySettings } from "./session/memory-settings-hydration.js";
|
|
14
15
|
import { FactoryTransitionService } from "./rules/transition-service.js";
|
|
16
|
+
import { SourceControlStorage } from "./storage/domains/source-control/base.js";
|
|
15
17
|
import { hydrateSessionModelPack } from "./session/model-pack-hydration.js";
|
|
16
18
|
import { observeSessionFilesystem } from "./session/filesystem-capture.js";
|
|
17
19
|
import { ModelCredentialsStorage } from "./storage/domains/credentials/base.js";
|
|
18
20
|
import { FactoryWorkspaceRegistry, createWorkspaceFactory } from "./workspace.js";
|
|
19
21
|
import { createTenantCredentialPrimer, primeTenantCredentials, registerTenantCredentialResolver } from "./routes/tenant-credentials.js";
|
|
20
22
|
import { QueueHealthStorage } from "./storage/domains/queue-health/base.js";
|
|
21
|
-
import { WorkItemsStorage } from "./storage/domains/work-items/base.js";
|
|
22
23
|
import { assembleFactoryApiRoutes, buildIntegrationContext } from "./routes/surface.js";
|
|
23
24
|
import { builtInFactoryRules } from "./rules/defaults.js";
|
|
24
25
|
import { FactoryDecisionDispatcher } from "./rules/dispatcher.js";
|
|
@@ -43,7 +44,6 @@ import { IntakeStorage } from "./storage/domains/intake/base.js";
|
|
|
43
44
|
import { IntegrationStorage } from "./storage/domains/integrations/base.js";
|
|
44
45
|
import { ModelPacksStorage } from "./storage/domains/model-packs/base.js";
|
|
45
46
|
import { FactoryProjectsStorage } from "./storage/domains/projects/base.js";
|
|
46
|
-
import { SourceControlStorage } from "./storage/domains/source-control/base.js";
|
|
47
47
|
import { hasAuthInit, isUserProvider } from "@mastra/core/server";
|
|
48
48
|
import { MastraAuthStudio } from "@mastra/auth-studio";
|
|
49
49
|
import { prepareAgentControllerMount } from "@mastra/code-sdk";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/integrations/github/rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,sBAAsB,CAAC;AAG9B,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;AAE9F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAEnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAwJxD,MAAM,WAAW,sBAAsB;IACrC,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,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,qBAAa,WAAW;;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAgBlD,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,CAAA;KAAE,CAAC;CA0YjH;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,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,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,mBAAmB,EAC/B,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,yBAAyB,GAC/B,mBAAmB,CA2BrB;AAgDD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,kBAAkB,EAC3B,gBAAgB,EAAE,wBAAwB,GACzC,2BAA2B,CAiJ7B;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,GAAG,SAAS,CAUhC;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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { changeRequestTargetKey } from "./subscriptions.js";
|
|
2
2
|
import { resolveFactoryGithubRule } from "../../rules/resolve.js";
|
|
3
|
+
import { isTerminalFactoryRuleStage } from "../../rules/types.js";
|
|
3
4
|
import { validateFactoryRuleDecisions } from "../../rules/validation.js";
|
|
5
|
+
import { FACTORY_PULL_REQUEST_RECONCILIATION_KEY } from "../../storage/domains/work-items/base.js";
|
|
4
6
|
//#region src/integrations/github/rules.ts
|
|
5
7
|
const TRUSTED_PERMISSIONS = /* @__PURE__ */ new Set(["write", "admin"]);
|
|
6
8
|
const RULE_TIMEOUT_MS = 5e3;
|
|
@@ -178,124 +180,148 @@ var GithubRules = class {
|
|
|
178
180
|
factoryAuthored: !senderIsResponder && provenance !== null || this.#isFactoryLogin(login)
|
|
179
181
|
});
|
|
180
182
|
if (actor.type === "github" && actor.factoryAuthored && (event === "issueCommentCreated" || event === "issueCommentEdited") && string(issueComment?.body)?.includes(FACTORY_TRIAGE_COMMENT_MARKER)) return { status: "ignored" };
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
+
const evaluate = async (item, ingressIdentity) => {
|
|
184
|
+
const context = {
|
|
185
|
+
tenant: {
|
|
186
|
+
orgId: project.orgId,
|
|
187
|
+
projectId: project.factoryProjectId
|
|
188
|
+
},
|
|
189
|
+
actor,
|
|
190
|
+
ingress: {
|
|
191
|
+
type: "github",
|
|
192
|
+
id: ingressIdentity
|
|
193
|
+
},
|
|
194
|
+
cause: `github.${event}`,
|
|
195
|
+
causalChain: [],
|
|
196
|
+
ruleSetVersion: this.options.rules.version,
|
|
197
|
+
...item ? {
|
|
198
|
+
item: {
|
|
199
|
+
id: item.id,
|
|
200
|
+
source: workItemSource(item),
|
|
201
|
+
sourceKey: workItemSourceKey(item),
|
|
202
|
+
parentWorkItemId: item.parentWorkItemId,
|
|
203
|
+
title: item.title,
|
|
204
|
+
url: item.externalSource?.url ?? null,
|
|
205
|
+
stages: item.stages,
|
|
206
|
+
metadata: item.metadata
|
|
207
|
+
},
|
|
208
|
+
board: item.externalSource?.type === "pull-request" ? "review" : "work",
|
|
209
|
+
itemRevision: item.revision
|
|
210
|
+
} : {},
|
|
211
|
+
event,
|
|
212
|
+
deliveryId: parsed.deliveryId,
|
|
213
|
+
factory: { createdAt: factoryProject.createdAt.toISOString() },
|
|
214
|
+
repository: {
|
|
215
|
+
id: repositoryId,
|
|
216
|
+
fullName: repositoryName
|
|
217
|
+
},
|
|
218
|
+
...issueNumber && string(issue?.title) && string(issue?.html_url) ? { issue: {
|
|
219
|
+
number: issueNumber,
|
|
220
|
+
title: string(issue?.title),
|
|
221
|
+
url: string(issue?.html_url),
|
|
222
|
+
...string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {},
|
|
223
|
+
...string(issue?.updated_at) ? { updatedAt: string(issue?.updated_at) } : {},
|
|
224
|
+
assignees: actorLogins(issue?.assignees),
|
|
225
|
+
labels: labelNames(issue?.labels),
|
|
226
|
+
...string(issue?.state) === "closed" || string(issue?.state) === "open" ? { state: string(issue?.state) } : {},
|
|
227
|
+
...string(issue?.state_reason) ? { stateReason: string(issue?.state_reason) } : {}
|
|
228
|
+
} } : {},
|
|
229
|
+
...event === "issueEdited" ? { issueChange: {
|
|
230
|
+
title: Boolean(object(changes?.title)),
|
|
231
|
+
body: Boolean(object(changes?.body))
|
|
232
|
+
} } : {},
|
|
233
|
+
...number(issueComment?.id) ? { issueComment: {
|
|
234
|
+
id: number(issueComment?.id),
|
|
235
|
+
...string(issueComment?.body) ? { body: string(issueComment?.body) } : {},
|
|
236
|
+
...string(issueComment?.html_url) ? { url: string(issueComment?.html_url) } : {},
|
|
237
|
+
...string(object(issueComment?.user)?.login) ? { author: string(object(issueComment?.user)?.login) } : {},
|
|
238
|
+
...string(object(issueComment?.user)?.type) ? { authorType: string(object(issueComment?.user)?.type) } : {},
|
|
239
|
+
...string(issueComment?.created_at) ? { createdAt: string(issueComment?.created_at) } : {},
|
|
240
|
+
...string(issueComment?.updated_at) ? { updatedAt: string(issueComment?.updated_at) } : {}
|
|
241
|
+
} } : {},
|
|
242
|
+
...pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url) ? { pullRequest: {
|
|
243
|
+
number: pullRequestNumber,
|
|
244
|
+
title: string(pullRequest?.title),
|
|
245
|
+
url: string(pullRequest?.html_url),
|
|
246
|
+
...string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {},
|
|
247
|
+
state: string(pullRequest?.state) === "closed" ? "closed" : "open",
|
|
248
|
+
draft: boolean(pullRequest?.draft) ?? false,
|
|
249
|
+
merged: boolean(pullRequest?.merged) ?? false,
|
|
250
|
+
assignees: actorLogins(pullRequest?.assignees),
|
|
251
|
+
requestedReviewers: actorLogins(pullRequest?.requested_reviewers),
|
|
252
|
+
labels: labelNames(pullRequest?.labels),
|
|
253
|
+
headBranch: string(object(pullRequest?.head)?.ref) ?? "",
|
|
254
|
+
baseBranch: string(object(pullRequest?.base)?.ref) ?? ""
|
|
255
|
+
} } : {},
|
|
256
|
+
...reviewRequested && requestedReviewer ? { reviewRequest: {
|
|
257
|
+
reviewer: requestedReviewer,
|
|
258
|
+
factoryReviewer: this.#isFactoryLogin(requestedReviewer)
|
|
259
|
+
} } : {},
|
|
260
|
+
...object(parsed.payload.review) ? { review: {
|
|
261
|
+
id: number(object(parsed.payload.review)?.id) ?? 0,
|
|
262
|
+
state: string(object(parsed.payload.review)?.state) ?? "unknown",
|
|
263
|
+
url: string(object(parsed.payload.review)?.html_url) ?? ""
|
|
264
|
+
} } : {}
|
|
265
|
+
};
|
|
266
|
+
const rule = resolveFactoryGithubRule(this.options.rules, event);
|
|
267
|
+
let decision;
|
|
268
|
+
let decisions = [];
|
|
269
|
+
let outcome = { status: "accepted" };
|
|
270
|
+
try {
|
|
271
|
+
decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : void 0;
|
|
272
|
+
if (decision?.type === "reject") outcome = {
|
|
273
|
+
status: "rejected",
|
|
274
|
+
code: decision.code,
|
|
275
|
+
reason: decision.reason
|
|
276
|
+
};
|
|
277
|
+
else if (decision) decisions = validateFactoryRuleDecisions([decision]).map((entry) => ({ ...entry }));
|
|
278
|
+
} catch (error) {
|
|
279
|
+
const timedOut = error instanceof Error && error.message === "FACTORY_RULE_TIMEOUT";
|
|
280
|
+
outcome = {
|
|
281
|
+
status: "rejected",
|
|
282
|
+
code: timedOut ? "timeout" : "rule_error",
|
|
283
|
+
reason: timedOut ? "Factory rule evaluation timed out." : error instanceof Error ? error.message.slice(0, 2e3) : "Factory GitHub rule failed."
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return { status: (await this.options.storage.commitRuleEvaluation({
|
|
183
287
|
orgId: project.orgId,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
id: `${installationId}:${parsed.deliveryId}`
|
|
190
|
-
},
|
|
191
|
-
cause: `github.${event}`,
|
|
192
|
-
causalChain: [],
|
|
193
|
-
ruleSetVersion: this.options.rules.version,
|
|
194
|
-
...relatedItem ? {
|
|
195
|
-
item: {
|
|
196
|
-
id: relatedItem.id,
|
|
197
|
-
source: workItemSource(relatedItem),
|
|
198
|
-
sourceKey: workItemSourceKey(relatedItem),
|
|
199
|
-
parentWorkItemId: relatedItem.parentWorkItemId,
|
|
200
|
-
title: relatedItem.title,
|
|
201
|
-
url: relatedItem.externalSource?.url ?? null,
|
|
202
|
-
stages: relatedItem.stages,
|
|
203
|
-
metadata: relatedItem.metadata
|
|
288
|
+
factoryProjectId: project.factoryProjectId,
|
|
289
|
+
workItemId: item?.id ?? null,
|
|
290
|
+
ingress: {
|
|
291
|
+
identity: ingressIdentity,
|
|
292
|
+
triggerType: `github.${event}`
|
|
204
293
|
},
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
fullName: repositoryName
|
|
214
|
-
},
|
|
215
|
-
...issueNumber && string(issue?.title) && string(issue?.html_url) ? { issue: {
|
|
216
|
-
number: issueNumber,
|
|
217
|
-
title: string(issue?.title),
|
|
218
|
-
url: string(issue?.html_url),
|
|
219
|
-
...string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {},
|
|
220
|
-
...string(issue?.updated_at) ? { updatedAt: string(issue?.updated_at) } : {},
|
|
221
|
-
assignees: actorLogins(issue?.assignees),
|
|
222
|
-
labels: labelNames(issue?.labels),
|
|
223
|
-
...string(issue?.state) === "closed" || string(issue?.state) === "open" ? { state: string(issue?.state) } : {},
|
|
224
|
-
...string(issue?.state_reason) ? { stateReason: string(issue?.state_reason) } : {}
|
|
225
|
-
} } : {},
|
|
226
|
-
...event === "issueEdited" ? { issueChange: {
|
|
227
|
-
title: Boolean(object(changes?.title)),
|
|
228
|
-
body: Boolean(object(changes?.body))
|
|
229
|
-
} } : {},
|
|
230
|
-
...number(issueComment?.id) ? { issueComment: {
|
|
231
|
-
id: number(issueComment?.id),
|
|
232
|
-
...string(issueComment?.body) ? { body: string(issueComment?.body) } : {},
|
|
233
|
-
...string(issueComment?.html_url) ? { url: string(issueComment?.html_url) } : {},
|
|
234
|
-
...string(object(issueComment?.user)?.login) ? { author: string(object(issueComment?.user)?.login) } : {},
|
|
235
|
-
...string(object(issueComment?.user)?.type) ? { authorType: string(object(issueComment?.user)?.type) } : {},
|
|
236
|
-
...string(issueComment?.created_at) ? { createdAt: string(issueComment?.created_at) } : {},
|
|
237
|
-
...string(issueComment?.updated_at) ? { updatedAt: string(issueComment?.updated_at) } : {}
|
|
238
|
-
} } : {},
|
|
239
|
-
...pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url) ? { pullRequest: {
|
|
240
|
-
number: pullRequestNumber,
|
|
241
|
-
title: string(pullRequest?.title),
|
|
242
|
-
url: string(pullRequest?.html_url),
|
|
243
|
-
...string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {},
|
|
244
|
-
state: string(pullRequest?.state) === "closed" ? "closed" : "open",
|
|
245
|
-
draft: boolean(pullRequest?.draft) ?? false,
|
|
246
|
-
merged: boolean(pullRequest?.merged) ?? false,
|
|
247
|
-
assignees: actorLogins(pullRequest?.assignees),
|
|
248
|
-
requestedReviewers: actorLogins(pullRequest?.requested_reviewers),
|
|
249
|
-
labels: labelNames(pullRequest?.labels),
|
|
250
|
-
headBranch: string(object(pullRequest?.head)?.ref) ?? "",
|
|
251
|
-
baseBranch: string(object(pullRequest?.base)?.ref) ?? ""
|
|
252
|
-
} } : {},
|
|
253
|
-
...reviewRequested && requestedReviewer ? { reviewRequest: {
|
|
254
|
-
reviewer: requestedReviewer,
|
|
255
|
-
factoryReviewer: this.#isFactoryLogin(requestedReviewer)
|
|
256
|
-
} } : {},
|
|
257
|
-
...object(parsed.payload.review) ? { review: {
|
|
258
|
-
id: number(object(parsed.payload.review)?.id) ?? 0,
|
|
259
|
-
state: string(object(parsed.payload.review)?.state) ?? "unknown",
|
|
260
|
-
url: string(object(parsed.payload.review)?.html_url) ?? ""
|
|
261
|
-
} } : {}
|
|
294
|
+
ruleSetVersion: this.options.rules.version,
|
|
295
|
+
expectedRevision: item?.revision ?? null,
|
|
296
|
+
actor: { ...actor },
|
|
297
|
+
outcome,
|
|
298
|
+
decisions,
|
|
299
|
+
causalChain: [],
|
|
300
|
+
now: /* @__PURE__ */ new Date()
|
|
301
|
+
})).status };
|
|
262
302
|
};
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
factoryProjectId: project.factoryProjectId,
|
|
286
|
-
workItemId: relatedItem?.id ?? null,
|
|
287
|
-
ingress: {
|
|
288
|
-
identity: `${installationId}:${parsed.deliveryId}`,
|
|
289
|
-
triggerType: `github.${event}`
|
|
290
|
-
},
|
|
291
|
-
ruleSetVersion: this.options.rules.version,
|
|
292
|
-
expectedRevision: relatedItem?.revision ?? null,
|
|
293
|
-
actor: { ...actor },
|
|
294
|
-
outcome,
|
|
295
|
-
decisions,
|
|
296
|
-
causalChain: [],
|
|
297
|
-
now: /* @__PURE__ */ new Date()
|
|
298
|
-
})).status };
|
|
303
|
+
const deliveryIdentity = `${installationId}:${parsed.deliveryId}`;
|
|
304
|
+
const primary = await evaluate(relatedItem, deliveryIdentity);
|
|
305
|
+
const linked = event === "pullRequestMerged" && relatedItem && pullRequestNumber ? await this.#linkedClosureItem(project.orgId, project.factoryProjectId, repositoryId, repositoryName, pullRequestNumber, relatedItem) : void 0;
|
|
306
|
+
if (!linked) return primary;
|
|
307
|
+
const secondary = await evaluate(linked, `${deliveryIdentity}:${linked.id}`);
|
|
308
|
+
for (const status of ["committed", "replayed"]) if (primary.status === status || secondary.status === status) return { status };
|
|
309
|
+
return primary;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* The other card a closed pull request concerns, joined through the Review
|
|
313
|
+
* card's `parentWorkItemId` — the link `upsertLinkedWorkItem` records when the
|
|
314
|
+
* pull request is opened, and therefore an exact join that needs no branch
|
|
315
|
+
* heuristics. Returns nothing when the pull request has only one card, which
|
|
316
|
+
* is every pull request Factory did not open from a work item's session.
|
|
317
|
+
*/
|
|
318
|
+
async #linkedClosureItem(orgId, projectId, repositoryId, repositoryFullName, pullRequestNumber, resolved) {
|
|
319
|
+
const items = await this.options.storage.list({
|
|
320
|
+
orgId,
|
|
321
|
+
factoryProjectId: projectId
|
|
322
|
+
});
|
|
323
|
+
const linked = resolved.externalSource?.type === "pull-request" ? items.find((item) => item.id === resolved.parentWorkItemId) : items.find((item) => item.parentWorkItemId === resolved.id && (item.externalSource?.externalId === canonicalSourceKey("pull-request", pullRequestNumber) || item.externalSource?.externalId === legacySourceKey(repositoryId, "pull-request", pullRequestNumber)) && cardBelongsToRepository(item, repositoryId, repositoryFullName));
|
|
324
|
+
return linked?.id === resolved.id ? void 0 : linked;
|
|
299
325
|
}
|
|
300
326
|
async #relatedItem(orgId, projectId, repositoryId, repositoryFullName, issueNumber, pullRequestNumber, pullRequestHeadBranch, provenance, preferAuthoringItem = false) {
|
|
301
327
|
const items = await this.options.storage.list({
|
|
@@ -418,6 +444,22 @@ function reconciledClosedEvent(repository, pullRequestNumber, state) {
|
|
|
418
444
|
}
|
|
419
445
|
};
|
|
420
446
|
}
|
|
447
|
+
function reconciledPullRequestMetadata(state, reconciliation) {
|
|
448
|
+
return {
|
|
449
|
+
state: state.state,
|
|
450
|
+
draft: state.draft,
|
|
451
|
+
merged: state.merged,
|
|
452
|
+
...state.author ? { author: state.author } : {},
|
|
453
|
+
...state.assignees ? { assignees: state.assignees } : {},
|
|
454
|
+
...state.requestedReviewers ? { requestedReviewers: state.requestedReviewers } : {},
|
|
455
|
+
...state.labels ? { labels: state.labels } : {},
|
|
456
|
+
[FACTORY_PULL_REQUEST_RECONCILIATION_KEY]: reconciliation === "settled" ? state.merged ? "merged" : "closed" : null
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function reconciledPullRequestOutcome(metadata) {
|
|
460
|
+
if (metadata.state !== "closed" || typeof metadata.merged !== "boolean") return void 0;
|
|
461
|
+
return metadata.merged ? "merged" : "closed";
|
|
462
|
+
}
|
|
421
463
|
/**
|
|
422
464
|
* The webhook handler retires subscriptions itself; the sweep replays only the
|
|
423
465
|
* rules ingress, so without this the thread's PR chip and the workspace row
|
|
@@ -479,8 +521,9 @@ function createGithubPullRequestReconciler(options, fetchPullRequest) {
|
|
|
479
521
|
const pullRequestNumber = reconcilablePullRequestNumber(item, repository);
|
|
480
522
|
if (!pullRequestNumber) continue;
|
|
481
523
|
const metadata = item.metadata ?? {};
|
|
482
|
-
const
|
|
483
|
-
|
|
524
|
+
const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];
|
|
525
|
+
const reconciledOutcome = reconciledPullRequestOutcome(metadata);
|
|
526
|
+
if ((stage === "done" || stage === "canceled") && reconciledOutcome !== void 0 && reconciliation === reconciledOutcome) continue;
|
|
484
527
|
const cards = cardsByNumber.get(pullRequestNumber) ?? [];
|
|
485
528
|
cards.push(item);
|
|
486
529
|
cardsByNumber.set(pullRequestNumber, cards);
|
|
@@ -499,35 +542,58 @@ function createGithubPullRequestReconciler(options, fetchPullRequest) {
|
|
|
499
542
|
summary.checked += 1;
|
|
500
543
|
if (!state) continue;
|
|
501
544
|
for (const card of cards) {
|
|
545
|
+
if (state.state === "closed") continue;
|
|
502
546
|
const metadata = card.metadata ?? {};
|
|
503
547
|
const statusChanged = metadata.state !== state.state || metadata.draft !== state.draft || metadata.merged !== state.merged;
|
|
504
548
|
const authorChanged = state.author !== void 0 && metadata.author !== state.author;
|
|
505
549
|
const assigneesChanged = !sameStrings(metadata.assignees, state.assignees);
|
|
506
550
|
const reviewersChanged = !sameStrings(metadata.requestedReviewers, state.requestedReviewers);
|
|
507
551
|
const labelsChanged = !sameStrings(metadata.labels, state.labels);
|
|
508
|
-
|
|
552
|
+
const metadataChanged = statusChanged || authorChanged || assigneesChanged || reviewersChanged || labelsChanged;
|
|
553
|
+
const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];
|
|
554
|
+
if (!metadataChanged && reconciliation !== "merged" && reconciliation !== "closed") continue;
|
|
509
555
|
try {
|
|
510
556
|
await options.storage.update({
|
|
511
557
|
orgId: card.orgId,
|
|
512
558
|
id: card.id,
|
|
513
559
|
userId: "factory-rule-dispatcher",
|
|
514
|
-
patch: { metadata:
|
|
515
|
-
state: state.state,
|
|
516
|
-
draft: state.draft,
|
|
517
|
-
merged: state.merged,
|
|
518
|
-
...state.author ? { author: state.author } : {},
|
|
519
|
-
...state.assignees ? { assignees: state.assignees } : {},
|
|
520
|
-
...state.requestedReviewers ? { requestedReviewers: state.requestedReviewers } : {},
|
|
521
|
-
...state.labels ? { labels: state.labels } : {}
|
|
522
|
-
} }
|
|
560
|
+
patch: { metadata: reconciledPullRequestMetadata(state, "clear") }
|
|
523
561
|
});
|
|
524
562
|
} catch (error) {
|
|
525
563
|
recordFailure(repository, error, pullRequestNumber);
|
|
526
564
|
}
|
|
527
565
|
}
|
|
528
566
|
if (state.state !== "closed") continue;
|
|
567
|
+
const cleanupFailures = /* @__PURE__ */ new Set();
|
|
568
|
+
for (const card of cards) {
|
|
569
|
+
if (!isTerminalFactoryRuleStage(card.stages)) continue;
|
|
570
|
+
try {
|
|
571
|
+
await options.storage.supersedeDecisionsForWorkItem({
|
|
572
|
+
orgId: card.orgId,
|
|
573
|
+
factoryProjectId: card.factoryProjectId,
|
|
574
|
+
workItemId: card.id,
|
|
575
|
+
supersededAt: /* @__PURE__ */ new Date()
|
|
576
|
+
});
|
|
577
|
+
} catch (error) {
|
|
578
|
+
recordFailure(repository, error, pullRequestNumber);
|
|
579
|
+
cleanupFailures.add(card.id);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
529
582
|
await rules.ingest(reconciledClosedEvent(repository, pullRequestNumber, state));
|
|
530
583
|
await retireReconciledSubscriptions(options.integrationStorage, repository, pullRequestNumber, state.merged);
|
|
584
|
+
for (const card of cards) {
|
|
585
|
+
if (cleanupFailures.has(card.id)) continue;
|
|
586
|
+
try {
|
|
587
|
+
await options.storage.update({
|
|
588
|
+
orgId: card.orgId,
|
|
589
|
+
id: card.id,
|
|
590
|
+
userId: "factory-rule-dispatcher",
|
|
591
|
+
patch: { metadata: reconciledPullRequestMetadata(state, "settled") }
|
|
592
|
+
});
|
|
593
|
+
} catch (error) {
|
|
594
|
+
recordFailure(repository, error, pullRequestNumber);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
531
597
|
if (state.merged) summary.merged += 1;
|
|
532
598
|
else summary.closed += 1;
|
|
533
599
|
} catch (error) {
|