@renseiai/agentfactory 0.8.7 → 0.8.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/dist/src/config/repository-config.d.ts +14 -0
- package/dist/src/config/repository-config.d.ts.map +1 -1
- package/dist/src/config/repository-config.js +20 -0
- package/dist/src/governor/event-types.d.ts +18 -1
- package/dist/src/governor/event-types.d.ts.map +1 -1
- package/dist/src/governor/event-types.js +4 -0
- package/dist/src/merge-queue/adapters/github-native.d.ts +22 -0
- package/dist/src/merge-queue/adapters/github-native.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/github-native.js +243 -0
- package/dist/src/merge-queue/adapters/github-native.test.d.ts +2 -0
- package/dist/src/merge-queue/adapters/github-native.test.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/github-native.test.js +384 -0
- package/dist/src/merge-queue/index.d.ts +18 -0
- package/dist/src/merge-queue/index.d.ts.map +1 -0
- package/dist/src/merge-queue/index.js +28 -0
- package/dist/src/merge-queue/merge-queue.integration.test.d.ts +2 -0
- package/dist/src/merge-queue/merge-queue.integration.test.d.ts.map +1 -0
- package/dist/src/merge-queue/merge-queue.integration.test.js +128 -0
- package/dist/src/merge-queue/types.d.ts +48 -0
- package/dist/src/merge-queue/types.d.ts.map +1 -0
- package/dist/src/merge-queue/types.js +8 -0
- package/dist/src/orchestrator/artifact-tracker.d.ts +93 -0
- package/dist/src/orchestrator/artifact-tracker.d.ts.map +1 -0
- package/dist/src/orchestrator/artifact-tracker.js +235 -0
- package/dist/src/orchestrator/artifact-tracker.test.d.ts +2 -0
- package/dist/src/orchestrator/artifact-tracker.test.d.ts.map +1 -0
- package/dist/src/orchestrator/artifact-tracker.test.js +189 -0
- package/dist/src/orchestrator/context-manager.d.ts +72 -0
- package/dist/src/orchestrator/context-manager.d.ts.map +1 -0
- package/dist/src/orchestrator/context-manager.js +120 -0
- package/dist/src/orchestrator/context-manager.test.d.ts +2 -0
- package/dist/src/orchestrator/context-manager.test.d.ts.map +1 -0
- package/dist/src/orchestrator/context-manager.test.js +137 -0
- package/dist/src/orchestrator/index.d.ts +8 -2
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +8 -1
- package/dist/src/orchestrator/orchestrator.d.ts +12 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/src/orchestrator/orchestrator.js +258 -2
- package/dist/src/orchestrator/state-recovery.d.ts +21 -2
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -1
- package/dist/src/orchestrator/state-recovery.js +54 -2
- package/dist/src/orchestrator/state-recovery.test.js +106 -2
- package/dist/src/orchestrator/state-types.d.ts +62 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -1
- package/dist/src/orchestrator/state-types.js +5 -1
- package/dist/src/orchestrator/summary-builder.d.ts +47 -0
- package/dist/src/orchestrator/summary-builder.d.ts.map +1 -0
- package/dist/src/orchestrator/summary-builder.js +240 -0
- package/dist/src/orchestrator/summary-builder.test.d.ts +2 -0
- package/dist/src/orchestrator/summary-builder.test.d.ts.map +1 -0
- package/dist/src/orchestrator/summary-builder.test.js +236 -0
- package/dist/src/orchestrator/types.d.ts +2 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -1
- package/dist/src/orchestrator/work-types.d.ts +1 -1
- package/dist/src/orchestrator/work-types.d.ts.map +1 -1
- package/dist/src/templates/registry.test.js +2 -2
- package/dist/src/templates/types.d.ts +2 -0
- package/dist/src/templates/types.d.ts.map +1 -1
- package/dist/src/templates/types.js +1 -0
- package/dist/src/workflow/branching-router.d.ts +38 -0
- package/dist/src/workflow/branching-router.d.ts.map +1 -0
- package/dist/src/workflow/branching-router.js +52 -0
- package/dist/src/workflow/branching-router.test.d.ts +2 -0
- package/dist/src/workflow/branching-router.test.d.ts.map +1 -0
- package/dist/src/workflow/branching-router.test.js +209 -0
- package/dist/src/workflow/duration.d.ts +28 -0
- package/dist/src/workflow/duration.d.ts.map +1 -0
- package/dist/src/workflow/duration.js +57 -0
- package/dist/src/workflow/duration.test.d.ts +2 -0
- package/dist/src/workflow/duration.test.d.ts.map +1 -0
- package/dist/src/workflow/duration.test.js +74 -0
- package/dist/src/workflow/expression/ast.d.ts +53 -0
- package/dist/src/workflow/expression/ast.d.ts.map +1 -0
- package/dist/src/workflow/expression/ast.js +8 -0
- package/dist/src/workflow/expression/context.d.ts +40 -0
- package/dist/src/workflow/expression/context.d.ts.map +1 -0
- package/dist/src/workflow/expression/context.js +37 -0
- package/dist/src/workflow/expression/evaluator.d.ts +28 -0
- package/dist/src/workflow/expression/evaluator.d.ts.map +1 -0
- package/dist/src/workflow/expression/evaluator.js +165 -0
- package/dist/src/workflow/expression/evaluator.test.d.ts +2 -0
- package/dist/src/workflow/expression/evaluator.test.d.ts.map +1 -0
- package/dist/src/workflow/expression/evaluator.test.js +792 -0
- package/dist/src/workflow/expression/expression.test.d.ts +2 -0
- package/dist/src/workflow/expression/expression.test.d.ts.map +1 -0
- package/dist/src/workflow/expression/expression.test.js +516 -0
- package/dist/src/workflow/expression/helpers.d.ts +21 -0
- package/dist/src/workflow/expression/helpers.d.ts.map +1 -0
- package/dist/src/workflow/expression/helpers.js +56 -0
- package/dist/src/workflow/expression/index.d.ts +55 -0
- package/dist/src/workflow/expression/index.d.ts.map +1 -0
- package/dist/src/workflow/expression/index.js +71 -0
- package/dist/src/workflow/expression/lexer.d.ts +37 -0
- package/dist/src/workflow/expression/lexer.d.ts.map +1 -0
- package/dist/src/workflow/expression/lexer.js +166 -0
- package/dist/src/workflow/expression/parser.d.ts +23 -0
- package/dist/src/workflow/expression/parser.d.ts.map +1 -0
- package/dist/src/workflow/expression/parser.js +181 -0
- package/dist/src/workflow/index.d.ts +10 -3
- package/dist/src/workflow/index.d.ts.map +1 -1
- package/dist/src/workflow/index.js +6 -1
- package/dist/src/workflow/retry-resolver.d.ts +51 -0
- package/dist/src/workflow/retry-resolver.d.ts.map +1 -0
- package/dist/src/workflow/retry-resolver.js +70 -0
- package/dist/src/workflow/retry-resolver.test.d.ts +2 -0
- package/dist/src/workflow/retry-resolver.test.d.ts.map +1 -0
- package/dist/src/workflow/retry-resolver.test.js +149 -0
- package/dist/src/workflow/transition-engine.d.ts +3 -1
- package/dist/src/workflow/transition-engine.d.ts.map +1 -1
- package/dist/src/workflow/transition-engine.js +14 -7
- package/dist/src/workflow/transition-engine.test.js +123 -11
- package/dist/src/workflow/workflow-registry.d.ts +41 -0
- package/dist/src/workflow/workflow-registry.d.ts.map +1 -1
- package/dist/src/workflow/workflow-registry.js +66 -0
- package/dist/src/workflow/workflow-types.d.ts +181 -8
- package/dist/src/workflow/workflow-types.d.ts.map +1 -1
- package/dist/src/workflow/workflow-types.js +31 -6
- package/package.json +2 -2
|
@@ -100,6 +100,20 @@ export declare const RepositoryConfigSchema: z.ZodObject<{
|
|
|
100
100
|
a2a: "a2a";
|
|
101
101
|
}>>>;
|
|
102
102
|
}, z.core.$strip>>;
|
|
103
|
+
mergeQueue: z.ZodOptional<z.ZodObject<{
|
|
104
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
105
|
+
"github-native": "github-native";
|
|
106
|
+
mergify: "mergify";
|
|
107
|
+
trunk: "trunk";
|
|
108
|
+
}>>;
|
|
109
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
110
|
+
autoMerge: z.ZodDefault<z.ZodBoolean>;
|
|
111
|
+
requiredChecks: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
112
|
+
}, z.core.$strip>>;
|
|
113
|
+
mergeDriver: z.ZodOptional<z.ZodEnum<{
|
|
114
|
+
default: "default";
|
|
115
|
+
mergiraf: "mergiraf";
|
|
116
|
+
}>>;
|
|
103
117
|
}, z.core.$strip>;
|
|
104
118
|
export type RepositoryConfig = z.infer<typeof RepositoryConfigSchema>;
|
|
105
119
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository-config.d.ts","sourceRoot":"","sources":["../../../src/config/repository-config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAM5D,qEAAqE;AACrE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAW9B,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAW/D,uCAAuC;AACvC,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAA;AAEF,eAAO,MAAM,sBAAsB
|
|
1
|
+
{"version":3,"file":"repository-config.d.ts","sourceRoot":"","sources":["../../../src/config/repository-config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAM5D,qEAAqE;AACrE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAW9B,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAW/D,uCAAuC;AACvC,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAA;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuElC,CAAA;AAMD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAMrE;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,GAAG,SAAS,CAK1F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAepG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKhG;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,eAAe,GAAG,SAAS,CAExF;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ7E"}
|
|
@@ -90,6 +90,26 @@ export const RepositoryConfigSchema = z.object({
|
|
|
90
90
|
* Allows routing agents to different providers by work type or project.
|
|
91
91
|
*/
|
|
92
92
|
providers: ProvidersConfigSchema.optional(),
|
|
93
|
+
/**
|
|
94
|
+
* Merge queue configuration.
|
|
95
|
+
* Controls which merge queue provider agents use for automated merging.
|
|
96
|
+
*/
|
|
97
|
+
mergeQueue: z.object({
|
|
98
|
+
/** Merge queue provider to use */
|
|
99
|
+
provider: z.enum(['github-native', 'mergify', 'trunk']).default('github-native'),
|
|
100
|
+
/** Whether merge queue integration is enabled */
|
|
101
|
+
enabled: z.boolean().default(false),
|
|
102
|
+
/** Automatically add approved PRs to merge queue */
|
|
103
|
+
autoMerge: z.boolean().default(true),
|
|
104
|
+
/** Required CI checks that must pass before merge (provider-specific) */
|
|
105
|
+
requiredChecks: z.array(z.string()).optional(),
|
|
106
|
+
}).optional(),
|
|
107
|
+
/**
|
|
108
|
+
* Git merge driver to use in agent worktrees.
|
|
109
|
+
* 'mergiraf' enables syntax-aware merging for supported file types.
|
|
110
|
+
* Defaults to 'default' (standard git line-based merge).
|
|
111
|
+
*/
|
|
112
|
+
mergeDriver: z.enum(['mergiraf', 'default']).optional(),
|
|
93
113
|
}).refine((data) => !(data.allowedProjects && data.projectPaths), { message: 'allowedProjects and projectPaths are mutually exclusive — use one or the other' });
|
|
94
114
|
// ---------------------------------------------------------------------------
|
|
95
115
|
// Helpers
|
|
@@ -64,8 +64,25 @@ export interface PollSnapshotEvent {
|
|
|
64
64
|
timestamp: string;
|
|
65
65
|
source: EventSource;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Fired when a nudge action is taken on a stuck agent session.
|
|
69
|
+
* Tracks nudge lifecycle: sent, succeeded (activity resumed), or failed (escalated).
|
|
70
|
+
*/
|
|
71
|
+
export interface NudgeEvent {
|
|
72
|
+
type: 'nudge-sent' | 'nudge-succeeded' | 'nudge-failed';
|
|
73
|
+
sessionId: string;
|
|
74
|
+
issueId: string;
|
|
75
|
+
issueIdentifier: string;
|
|
76
|
+
workerId: string;
|
|
77
|
+
attemptNumber: number;
|
|
78
|
+
nudgeMessage: string;
|
|
79
|
+
reason: string;
|
|
80
|
+
/** ISO-8601 timestamp */
|
|
81
|
+
timestamp: string;
|
|
82
|
+
source: EventSource;
|
|
83
|
+
}
|
|
67
84
|
export type EventSource = 'webhook' | 'poll' | 'manual';
|
|
68
|
-
export type GovernorEvent = IssueStatusChangedEvent | CommentAddedEvent | SessionCompletedEvent | PollSnapshotEvent;
|
|
85
|
+
export type GovernorEvent = IssueStatusChangedEvent | CommentAddedEvent | SessionCompletedEvent | PollSnapshotEvent | NudgeEvent;
|
|
69
86
|
/**
|
|
70
87
|
* Generate a deduplication key for an event.
|
|
71
88
|
* Same issue at the same status = duplicate within the dedup window.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../../../src/governor/event-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMxD;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,sBAAsB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,kCAAkC;IAClC,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAA;IAC9B,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAMD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAMvD,MAAM,MAAM,aAAa,GACrB,uBAAuB,GACvB,iBAAiB,GACjB,qBAAqB,GACrB,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"event-types.d.ts","sourceRoot":"","sources":["../../../src/governor/event-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMxD;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,sBAAsB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,kCAAkC;IAClC,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,mBAAmB,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,SAAS,GAAG,SAAS,CAAA;IAC9B,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,GAAG,iBAAiB,GAAG,cAAc,CAAA;IACvD,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;CACpB;AAMD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAMvD,MAAM,MAAM,aAAa,GACrB,uBAAuB,GACvB,iBAAiB,GACjB,qBAAqB,GACrB,iBAAiB,GACjB,UAAU,CAAA;AAMd;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAe1D;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
|
|
@@ -22,6 +22,10 @@ export function eventDedupKey(event) {
|
|
|
22
22
|
return `${event.issueId}:session:${event.sessionId}`;
|
|
23
23
|
case 'poll-snapshot':
|
|
24
24
|
return `${event.issueId}:${event.issue.status}`;
|
|
25
|
+
case 'nudge-sent':
|
|
26
|
+
case 'nudge-succeeded':
|
|
27
|
+
case 'nudge-failed':
|
|
28
|
+
return `${event.sessionId}:nudge:${event.type}:${event.attemptNumber}`;
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Native Merge Queue Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements MergeQueueAdapter for GitHub's built-in merge queue feature.
|
|
5
|
+
* Uses `gh api graphql` CLI for all GitHub API interactions.
|
|
6
|
+
*/
|
|
7
|
+
import type { MergeQueueAdapter, MergeQueueStatus } from '../types.js';
|
|
8
|
+
export declare class GitHubNativeMergeQueueAdapter implements MergeQueueAdapter {
|
|
9
|
+
readonly name: "github-native";
|
|
10
|
+
canEnqueue(owner: string, repo: string, prNumber: number): Promise<boolean>;
|
|
11
|
+
enqueue(owner: string, repo: string, prNumber: number): Promise<MergeQueueStatus>;
|
|
12
|
+
getStatus(owner: string, repo: string, prNumber: number): Promise<MergeQueueStatus>;
|
|
13
|
+
dequeue(owner: string, repo: string, prNumber: number): Promise<void>;
|
|
14
|
+
isEnabled(owner: string, repo: string): Promise<boolean>;
|
|
15
|
+
/** Get the GraphQL node ID for a PR */
|
|
16
|
+
private getPRNodeId;
|
|
17
|
+
/** Execute a GraphQL query/mutation via gh CLI with retry */
|
|
18
|
+
private graphql;
|
|
19
|
+
/** Map GitHub merge queue entry to our MergeQueueStatus */
|
|
20
|
+
private mapEntryToStatus;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=github-native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-native.d.ts","sourceRoot":"","sources":["../../../../src/merge-queue/adapters/github-native.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAatE,qBAAa,6BAA8B,YAAW,iBAAiB;IACrE,QAAQ,CAAC,IAAI,EAAG,eAAe,CAAS;IAElC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA6C3E,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwCjF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+FnF,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBrE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmC9D,uCAAuC;YACzB,WAAW;IAiBzB,6DAA6D;YAC/C,OAAO;IAgCrB,2DAA2D;IAC3D,OAAO,CAAC,gBAAgB;CAgBzB"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Native Merge Queue Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements MergeQueueAdapter for GitHub's built-in merge queue feature.
|
|
5
|
+
* Uses `gh api graphql` CLI for all GitHub API interactions.
|
|
6
|
+
*/
|
|
7
|
+
import { exec } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
/** Timeout for GitHub API calls (30s) */
|
|
11
|
+
const GH_API_TIMEOUT = 30000;
|
|
12
|
+
/** Maximum retries for transient failures */
|
|
13
|
+
const MAX_RETRIES = 2;
|
|
14
|
+
/** Backoff delay between retries (ms) */
|
|
15
|
+
const RETRY_DELAY = 1000;
|
|
16
|
+
export class GitHubNativeMergeQueueAdapter {
|
|
17
|
+
name = 'github-native';
|
|
18
|
+
async canEnqueue(owner, repo, prNumber) {
|
|
19
|
+
try {
|
|
20
|
+
const query = `
|
|
21
|
+
query($owner: String!, $repo: String!, $prNumber: Int!) {
|
|
22
|
+
repository(owner: $owner, name: $repo) {
|
|
23
|
+
pullRequest(number: $prNumber) {
|
|
24
|
+
mergeable
|
|
25
|
+
reviewDecision
|
|
26
|
+
mergeQueueEntry { state }
|
|
27
|
+
baseRef {
|
|
28
|
+
branchProtectionRule {
|
|
29
|
+
requiresStatusChecks
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
const result = await this.graphql(query, { owner, repo, prNumber });
|
|
37
|
+
const pr = result.repository.pullRequest;
|
|
38
|
+
// Already in queue
|
|
39
|
+
if (pr.mergeQueueEntry)
|
|
40
|
+
return false;
|
|
41
|
+
// Must be mergeable
|
|
42
|
+
if (pr.mergeable !== 'MERGEABLE')
|
|
43
|
+
return false;
|
|
44
|
+
// Must be approved (if reviews are required)
|
|
45
|
+
if (pr.reviewDecision && pr.reviewDecision !== 'APPROVED')
|
|
46
|
+
return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async enqueue(owner, repo, prNumber) {
|
|
54
|
+
// First get the PR's node ID
|
|
55
|
+
const prId = await this.getPRNodeId(owner, repo, prNumber);
|
|
56
|
+
const mutation = `
|
|
57
|
+
mutation($prId: ID!) {
|
|
58
|
+
enqueuePullRequest(input: { pullRequestId: $prId }) {
|
|
59
|
+
mergeQueueEntry {
|
|
60
|
+
state
|
|
61
|
+
position
|
|
62
|
+
headCommit { oid }
|
|
63
|
+
enqueuedAt
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
try {
|
|
69
|
+
const result = await this.graphql(mutation, { prId });
|
|
70
|
+
const entry = result.enqueuePullRequest.mergeQueueEntry;
|
|
71
|
+
return this.mapEntryToStatus(entry);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
state: 'failed',
|
|
76
|
+
failureReason: error instanceof Error ? error.message : String(error),
|
|
77
|
+
checksStatus: [],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async getStatus(owner, repo, prNumber) {
|
|
82
|
+
const query = `
|
|
83
|
+
query($owner: String!, $repo: String!, $prNumber: Int!) {
|
|
84
|
+
repository(owner: $owner, name: $repo) {
|
|
85
|
+
pullRequest(number: $prNumber) {
|
|
86
|
+
mergeQueueEntry {
|
|
87
|
+
state
|
|
88
|
+
position
|
|
89
|
+
headCommit { oid }
|
|
90
|
+
enqueuedAt
|
|
91
|
+
}
|
|
92
|
+
commits(last: 1) {
|
|
93
|
+
nodes {
|
|
94
|
+
commit {
|
|
95
|
+
statusCheckRollup {
|
|
96
|
+
contexts(first: 50) {
|
|
97
|
+
nodes {
|
|
98
|
+
... on CheckRun {
|
|
99
|
+
name
|
|
100
|
+
conclusion
|
|
101
|
+
status
|
|
102
|
+
}
|
|
103
|
+
... on StatusContext {
|
|
104
|
+
context
|
|
105
|
+
state
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
const result = await this.graphql(query, { owner, repo, prNumber });
|
|
118
|
+
const pr = result.repository.pullRequest;
|
|
119
|
+
if (!pr.mergeQueueEntry) {
|
|
120
|
+
return { state: 'not-queued', checksStatus: [] };
|
|
121
|
+
}
|
|
122
|
+
const status = this.mapEntryToStatus(pr.mergeQueueEntry);
|
|
123
|
+
// Map check statuses
|
|
124
|
+
const commitNode = pr.commits.nodes[0];
|
|
125
|
+
if (commitNode?.commit.statusCheckRollup) {
|
|
126
|
+
status.checksStatus = commitNode.commit.statusCheckRollup.contexts.nodes.map((node) => {
|
|
127
|
+
if ('name' in node) {
|
|
128
|
+
return {
|
|
129
|
+
name: node.name,
|
|
130
|
+
status: node.conclusion === 'SUCCESS' ? 'pass'
|
|
131
|
+
: node.status === 'COMPLETED' ? 'fail'
|
|
132
|
+
: 'pending',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
name: node.context,
|
|
137
|
+
status: node.state === 'SUCCESS' ? 'pass'
|
|
138
|
+
: node.state === 'PENDING' ? 'pending'
|
|
139
|
+
: 'fail',
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return status;
|
|
144
|
+
}
|
|
145
|
+
async dequeue(owner, repo, prNumber) {
|
|
146
|
+
const prId = await this.getPRNodeId(owner, repo, prNumber);
|
|
147
|
+
const mutation = `
|
|
148
|
+
mutation($prId: ID!) {
|
|
149
|
+
dequeuePullRequest(input: { pullRequestId: $prId }) {
|
|
150
|
+
mergeQueueEntry {
|
|
151
|
+
state
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
`;
|
|
156
|
+
await this.graphql(mutation, { prId });
|
|
157
|
+
}
|
|
158
|
+
async isEnabled(owner, repo) {
|
|
159
|
+
try {
|
|
160
|
+
const query = `
|
|
161
|
+
query($owner: String!, $repo: String!) {
|
|
162
|
+
repository(owner: $owner, name: $repo) {
|
|
163
|
+
defaultBranchRef {
|
|
164
|
+
branchProtectionRule {
|
|
165
|
+
requiresMergeQueue
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
`;
|
|
171
|
+
// Note: requiresMergeQueue might not be available in all GitHub API versions.
|
|
172
|
+
// Fallback: check if merge queue entries exist
|
|
173
|
+
const result = await this.graphql(query, { owner, repo });
|
|
174
|
+
return result.repository.defaultBranchRef?.branchProtectionRule?.requiresMergeQueue ?? false;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Private helpers
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
/** Get the GraphQL node ID for a PR */
|
|
184
|
+
async getPRNodeId(owner, repo, prNumber) {
|
|
185
|
+
const query = `
|
|
186
|
+
query($owner: String!, $repo: String!, $prNumber: Int!) {
|
|
187
|
+
repository(owner: $owner, name: $repo) {
|
|
188
|
+
pullRequest(number: $prNumber) {
|
|
189
|
+
id
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
194
|
+
const result = await this.graphql(query, { owner, repo, prNumber });
|
|
195
|
+
return result.repository.pullRequest.id;
|
|
196
|
+
}
|
|
197
|
+
/** Execute a GraphQL query/mutation via gh CLI with retry */
|
|
198
|
+
async graphql(query, variables) {
|
|
199
|
+
const varsArgs = Object.entries(variables)
|
|
200
|
+
.map(([key, value]) => {
|
|
201
|
+
if (typeof value === 'number') {
|
|
202
|
+
return `-F ${key}=${value}`;
|
|
203
|
+
}
|
|
204
|
+
return `-f ${key}=${String(value)}`;
|
|
205
|
+
})
|
|
206
|
+
.join(' ');
|
|
207
|
+
const command = `gh api graphql -f query='${query.replace(/'/g, "'\\''")}' ${varsArgs}`;
|
|
208
|
+
let lastError = null;
|
|
209
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
210
|
+
try {
|
|
211
|
+
const { stdout } = await execAsync(command, { timeout: GH_API_TIMEOUT });
|
|
212
|
+
const response = JSON.parse(stdout);
|
|
213
|
+
if (response.errors?.length) {
|
|
214
|
+
throw new Error(response.errors.map((e) => e.message).join('; '));
|
|
215
|
+
}
|
|
216
|
+
return response.data;
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
220
|
+
if (attempt < MAX_RETRIES) {
|
|
221
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY * (attempt + 1)));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
throw lastError;
|
|
226
|
+
}
|
|
227
|
+
/** Map GitHub merge queue entry to our MergeQueueStatus */
|
|
228
|
+
mapEntryToStatus(entry) {
|
|
229
|
+
const stateMap = {
|
|
230
|
+
QUEUED: 'queued',
|
|
231
|
+
AWAITING_CHECKS: 'queued',
|
|
232
|
+
MERGEABLE: 'merging',
|
|
233
|
+
MERGED: 'merged',
|
|
234
|
+
UNMERGEABLE: 'failed',
|
|
235
|
+
LOCKED: 'blocked',
|
|
236
|
+
};
|
|
237
|
+
return {
|
|
238
|
+
state: stateMap[entry.state] ?? 'not-queued',
|
|
239
|
+
position: entry.position,
|
|
240
|
+
checksStatus: [],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-native.test.d.ts","sourceRoot":"","sources":["../../../../src/merge-queue/adapters/github-native.test.ts"],"names":[],"mappings":""}
|