@renseiai/agentfactory 0.8.6 → 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.
Files changed (175) hide show
  1. package/README.md +2 -2
  2. package/dist/src/config/repository-config.d.ts +14 -0
  3. package/dist/src/config/repository-config.d.ts.map +1 -1
  4. package/dist/src/config/repository-config.js +20 -0
  5. package/dist/src/governor/decision-engine.d.ts +7 -0
  6. package/dist/src/governor/decision-engine.d.ts.map +1 -1
  7. package/dist/src/governor/decision-engine.js +59 -1
  8. package/dist/src/governor/event-types.d.ts +18 -1
  9. package/dist/src/governor/event-types.d.ts.map +1 -1
  10. package/dist/src/governor/event-types.js +4 -0
  11. package/dist/src/governor/governor.d.ts +5 -1
  12. package/dist/src/governor/governor.d.ts.map +1 -1
  13. package/dist/src/governor/governor.js +6 -1
  14. package/dist/src/index.d.ts +1 -0
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/index.js +1 -0
  17. package/dist/src/merge-queue/adapters/github-native.d.ts +22 -0
  18. package/dist/src/merge-queue/adapters/github-native.d.ts.map +1 -0
  19. package/dist/src/merge-queue/adapters/github-native.js +243 -0
  20. package/dist/src/merge-queue/adapters/github-native.test.d.ts +2 -0
  21. package/dist/src/merge-queue/adapters/github-native.test.d.ts.map +1 -0
  22. package/dist/src/merge-queue/adapters/github-native.test.js +384 -0
  23. package/dist/src/merge-queue/index.d.ts +18 -0
  24. package/dist/src/merge-queue/index.d.ts.map +1 -0
  25. package/dist/src/merge-queue/index.js +28 -0
  26. package/dist/src/merge-queue/merge-queue.integration.test.d.ts +2 -0
  27. package/dist/src/merge-queue/merge-queue.integration.test.d.ts.map +1 -0
  28. package/dist/src/merge-queue/merge-queue.integration.test.js +128 -0
  29. package/dist/src/merge-queue/types.d.ts +48 -0
  30. package/dist/src/merge-queue/types.d.ts.map +1 -0
  31. package/dist/src/merge-queue/types.js +8 -0
  32. package/dist/src/orchestrator/activity-emitter.d.ts +3 -3
  33. package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -1
  34. package/dist/src/orchestrator/activity-emitter.js +1 -1
  35. package/dist/src/orchestrator/artifact-tracker.d.ts +93 -0
  36. package/dist/src/orchestrator/artifact-tracker.d.ts.map +1 -0
  37. package/dist/src/orchestrator/artifact-tracker.js +235 -0
  38. package/dist/src/orchestrator/artifact-tracker.test.d.ts +2 -0
  39. package/dist/src/orchestrator/artifact-tracker.test.d.ts.map +1 -0
  40. package/dist/src/orchestrator/artifact-tracker.test.js +189 -0
  41. package/dist/src/orchestrator/context-manager.d.ts +72 -0
  42. package/dist/src/orchestrator/context-manager.d.ts.map +1 -0
  43. package/dist/src/orchestrator/context-manager.js +120 -0
  44. package/dist/src/orchestrator/context-manager.test.d.ts +2 -0
  45. package/dist/src/orchestrator/context-manager.test.d.ts.map +1 -0
  46. package/dist/src/orchestrator/context-manager.test.js +137 -0
  47. package/dist/src/orchestrator/detect-work-type.test.js +25 -16
  48. package/dist/src/orchestrator/index.d.ts +12 -2
  49. package/dist/src/orchestrator/index.d.ts.map +1 -1
  50. package/dist/src/orchestrator/index.js +9 -1
  51. package/dist/src/orchestrator/issue-tracker-client.d.ts +103 -0
  52. package/dist/src/orchestrator/issue-tracker-client.d.ts.map +1 -0
  53. package/dist/src/orchestrator/issue-tracker-client.js +8 -0
  54. package/dist/src/orchestrator/log-analyzer.d.ts +19 -4
  55. package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -1
  56. package/dist/src/orchestrator/log-analyzer.js +26 -50
  57. package/dist/src/orchestrator/orchestrator-utils.test.js +3 -0
  58. package/dist/src/orchestrator/orchestrator.d.ts +16 -2
  59. package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
  60. package/dist/src/orchestrator/orchestrator.js +449 -115
  61. package/dist/src/orchestrator/parse-work-result.d.ts +1 -1
  62. package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -1
  63. package/dist/src/orchestrator/parse-work-result.js +1 -1
  64. package/dist/src/orchestrator/session-logger.d.ts +1 -1
  65. package/dist/src/orchestrator/session-logger.d.ts.map +1 -1
  66. package/dist/src/orchestrator/state-recovery.d.ts +22 -3
  67. package/dist/src/orchestrator/state-recovery.d.ts.map +1 -1
  68. package/dist/src/orchestrator/state-recovery.js +55 -2
  69. package/dist/src/orchestrator/state-recovery.test.js +106 -2
  70. package/dist/src/orchestrator/state-types.d.ts +63 -1
  71. package/dist/src/orchestrator/state-types.d.ts.map +1 -1
  72. package/dist/src/orchestrator/state-types.js +5 -1
  73. package/dist/src/orchestrator/summary-builder.d.ts +47 -0
  74. package/dist/src/orchestrator/summary-builder.d.ts.map +1 -0
  75. package/dist/src/orchestrator/summary-builder.js +240 -0
  76. package/dist/src/orchestrator/summary-builder.test.d.ts +2 -0
  77. package/dist/src/orchestrator/summary-builder.test.d.ts.map +1 -0
  78. package/dist/src/orchestrator/summary-builder.test.js +236 -0
  79. package/dist/src/orchestrator/types.d.ts +24 -2
  80. package/dist/src/orchestrator/types.d.ts.map +1 -1
  81. package/dist/src/orchestrator/work-types.d.ts +50 -0
  82. package/dist/src/orchestrator/work-types.d.ts.map +1 -0
  83. package/dist/src/orchestrator/work-types.js +20 -0
  84. package/dist/src/templates/registry.d.ts +1 -1
  85. package/dist/src/templates/registry.test.js +2 -2
  86. package/dist/src/templates/renderer.d.ts +1 -1
  87. package/dist/src/templates/types.d.ts +6 -2
  88. package/dist/src/templates/types.d.ts.map +1 -1
  89. package/dist/src/templates/types.js +2 -0
  90. package/dist/src/templates/types.test.js +4 -3
  91. package/dist/src/tools/index.d.ts +0 -3
  92. package/dist/src/tools/index.d.ts.map +1 -1
  93. package/dist/src/tools/index.js +0 -2
  94. package/dist/src/workflow/branching-router.d.ts +38 -0
  95. package/dist/src/workflow/branching-router.d.ts.map +1 -0
  96. package/dist/src/workflow/branching-router.js +52 -0
  97. package/dist/src/workflow/branching-router.test.d.ts +2 -0
  98. package/dist/src/workflow/branching-router.test.d.ts.map +1 -0
  99. package/dist/src/workflow/branching-router.test.js +209 -0
  100. package/dist/src/workflow/duration.d.ts +28 -0
  101. package/dist/src/workflow/duration.d.ts.map +1 -0
  102. package/dist/src/workflow/duration.js +57 -0
  103. package/dist/src/workflow/duration.test.d.ts +2 -0
  104. package/dist/src/workflow/duration.test.d.ts.map +1 -0
  105. package/dist/src/workflow/duration.test.js +74 -0
  106. package/dist/src/workflow/expression/ast.d.ts +53 -0
  107. package/dist/src/workflow/expression/ast.d.ts.map +1 -0
  108. package/dist/src/workflow/expression/ast.js +8 -0
  109. package/dist/src/workflow/expression/context.d.ts +40 -0
  110. package/dist/src/workflow/expression/context.d.ts.map +1 -0
  111. package/dist/src/workflow/expression/context.js +37 -0
  112. package/dist/src/workflow/expression/evaluator.d.ts +28 -0
  113. package/dist/src/workflow/expression/evaluator.d.ts.map +1 -0
  114. package/dist/src/workflow/expression/evaluator.js +165 -0
  115. package/dist/src/workflow/expression/evaluator.test.d.ts +2 -0
  116. package/dist/src/workflow/expression/evaluator.test.d.ts.map +1 -0
  117. package/dist/src/workflow/expression/evaluator.test.js +792 -0
  118. package/dist/src/workflow/expression/expression.test.d.ts +2 -0
  119. package/dist/src/workflow/expression/expression.test.d.ts.map +1 -0
  120. package/dist/src/workflow/expression/expression.test.js +516 -0
  121. package/dist/src/workflow/expression/helpers.d.ts +21 -0
  122. package/dist/src/workflow/expression/helpers.d.ts.map +1 -0
  123. package/dist/src/workflow/expression/helpers.js +56 -0
  124. package/dist/src/workflow/expression/index.d.ts +55 -0
  125. package/dist/src/workflow/expression/index.d.ts.map +1 -0
  126. package/dist/src/workflow/expression/index.js +71 -0
  127. package/dist/src/workflow/expression/lexer.d.ts +37 -0
  128. package/dist/src/workflow/expression/lexer.d.ts.map +1 -0
  129. package/dist/src/workflow/expression/lexer.js +166 -0
  130. package/dist/src/workflow/expression/parser.d.ts +23 -0
  131. package/dist/src/workflow/expression/parser.d.ts.map +1 -0
  132. package/dist/src/workflow/expression/parser.js +181 -0
  133. package/dist/src/workflow/index.d.ts +21 -0
  134. package/dist/src/workflow/index.d.ts.map +1 -0
  135. package/dist/src/workflow/index.js +15 -0
  136. package/dist/src/workflow/retry-resolver.d.ts +51 -0
  137. package/dist/src/workflow/retry-resolver.d.ts.map +1 -0
  138. package/dist/src/workflow/retry-resolver.js +70 -0
  139. package/dist/src/workflow/retry-resolver.test.d.ts +2 -0
  140. package/dist/src/workflow/retry-resolver.test.d.ts.map +1 -0
  141. package/dist/src/workflow/retry-resolver.test.js +149 -0
  142. package/dist/src/workflow/transition-engine.d.ts +46 -0
  143. package/dist/src/workflow/transition-engine.d.ts.map +1 -0
  144. package/dist/src/workflow/transition-engine.js +113 -0
  145. package/dist/src/workflow/transition-engine.test.d.ts +2 -0
  146. package/dist/src/workflow/transition-engine.test.d.ts.map +1 -0
  147. package/dist/src/workflow/transition-engine.test.js +425 -0
  148. package/dist/src/workflow/workflow-loader.d.ts +21 -0
  149. package/dist/src/workflow/workflow-loader.d.ts.map +1 -0
  150. package/dist/src/workflow/workflow-loader.js +40 -0
  151. package/dist/src/workflow/workflow-loader.test.d.ts +2 -0
  152. package/dist/src/workflow/workflow-loader.test.d.ts.map +1 -0
  153. package/dist/src/workflow/workflow-loader.test.js +134 -0
  154. package/dist/src/workflow/workflow-registry.d.ts +97 -0
  155. package/dist/src/workflow/workflow-registry.d.ts.map +1 -0
  156. package/dist/src/workflow/workflow-registry.js +173 -0
  157. package/dist/src/workflow/workflow-registry.test.d.ts +2 -0
  158. package/dist/src/workflow/workflow-registry.test.d.ts.map +1 -0
  159. package/dist/src/workflow/workflow-registry.test.js +201 -0
  160. package/dist/src/workflow/workflow-types.d.ts +442 -0
  161. package/dist/src/workflow/workflow-types.d.ts.map +1 -0
  162. package/dist/src/workflow/workflow-types.js +113 -0
  163. package/dist/src/workflow/workflow-types.test.d.ts +2 -0
  164. package/dist/src/workflow/workflow-types.test.d.ts.map +1 -0
  165. package/dist/src/workflow/workflow-types.test.js +440 -0
  166. package/package.json +3 -4
  167. package/dist/src/linear-cli.d.ts +0 -38
  168. package/dist/src/linear-cli.d.ts.map +0 -1
  169. package/dist/src/linear-cli.js +0 -674
  170. package/dist/src/tools/linear-runner.d.ts +0 -34
  171. package/dist/src/tools/linear-runner.d.ts.map +0 -1
  172. package/dist/src/tools/linear-runner.js +0 -700
  173. package/dist/src/tools/plugins/linear.d.ts +0 -9
  174. package/dist/src/tools/plugins/linear.d.ts.map +0 -1
  175. package/dist/src/tools/plugins/linear.js +0 -138
package/README.md CHANGED
@@ -7,7 +7,7 @@ Part of the [AgentFactory](https://github.com/renseiai/agentfactory) monorepo.
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- npm install @renseiai/agentfactory @renseiai/agentfactory-linear
10
+ npm install @renseiai/agentfactory @renseiai/plugin-linear
11
11
  ```
12
12
 
13
13
  ## Quick Start
@@ -115,7 +115,7 @@ The governor evaluates each issue against status, active sessions, cooldowns, hu
115
115
 
116
116
  | Package | Description |
117
117
  |---------|-------------|
118
- | [@renseiai/agentfactory-linear](https://www.npmjs.com/package/@renseiai/agentfactory-linear) | Linear issue tracker integration |
118
+ | [@renseiai/plugin-linear](https://www.npmjs.com/package/@renseiai/plugin-linear) | Linear issue tracker integration |
119
119
  | [@renseiai/agentfactory-server](https://www.npmjs.com/package/@renseiai/agentfactory-server) | Redis work queue, distributed workers |
120
120
  | [@renseiai/agentfactory-cli](https://www.npmjs.com/package/@renseiai/agentfactory-cli) | CLI tools |
121
121
  | [@renseiai/agentfactory-nextjs](https://www.npmjs.com/package/@renseiai/agentfactory-nextjs) | Next.js webhook server |
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmDlC,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"}
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
@@ -8,6 +8,7 @@
8
8
  * state, active sessions, cooldowns, and configuration flags.
9
9
  */
10
10
  import type { GovernorAction, GovernorConfig, GovernorIssue } from './governor-types.js';
11
+ import type { WorkflowRegistry } from '../workflow/workflow-registry.js';
11
12
  /**
12
13
  * All external state the Governor gathers before asking the decision engine
13
14
  * what to do. Callers are responsible for populating this context; the
@@ -25,6 +26,12 @@ export interface DecisionContext {
25
26
  backlogCreationCompleted: boolean;
26
27
  /** Number of completed agent sessions for this issue (for circuit breaker) */
27
28
  completedSessionCount: number;
29
+ /**
30
+ * Optional workflow registry for declarative transition routing.
31
+ * When present, the transition engine is used instead of the hard-coded
32
+ * switch statement. Falls back to the switch statement when absent.
33
+ */
34
+ workflowRegistry?: WorkflowRegistry;
28
35
  }
29
36
  /** Max agent sessions before the circuit breaker trips and the issue is held */
30
37
  export declare const MAX_SESSION_ATTEMPTS = 3;
@@ -1 +1 @@
1
- {"version":3,"file":"decision-engine.d.ts","sourceRoot":"","sources":["../../../src/governor/decision-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAWxF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAA;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,gBAAgB,EAAE,OAAO,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;IACf,gBAAgB,EAAE,OAAO,CAAA;IACzB,aAAa,EAAE,OAAO,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,wBAAwB,EAAE,OAAO,CAAA;IACjC,8EAA8E;IAC9E,qBAAqB,EAAE,MAAM,CAAA;CAC9B;AAED,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAMrC,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;CACf;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,CAsEjE"}
1
+ {"version":3,"file":"decision-engine.d.ts","sourceRoot":"","sources":["../../../src/governor/decision-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AAOxE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAA;IACpB,MAAM,EAAE,cAAc,CAAA;IACtB,gBAAgB,EAAE,OAAO,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;IACf,gBAAgB,EAAE,OAAO,CAAA;IACzB,aAAa,EAAE,OAAO,CAAA;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,wBAAwB,EAAE,OAAO,CAAA;IACjC,8EAA8E;IAC9E,qBAAqB,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC;AAED,gFAAgF;AAChF,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAMrC,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;CACf;AAaD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,CAsGjE"}
@@ -8,6 +8,7 @@
8
8
  * state, active sessions, cooldowns, and configuration flags.
9
9
  */
10
10
  import { determineTopOfFunnelAction, DEFAULT_TOP_OF_FUNNEL_CONFIG, } from './top-of-funnel.js';
11
+ import { evaluateTransitions } from '../workflow/transition-engine.js';
11
12
  /** Max agent sessions before the circuit breaker trips and the issue is held */
12
13
  export const MAX_SESSION_ATTEMPTS = 3;
13
14
  // ---------------------------------------------------------------------------
@@ -71,7 +72,35 @@ export function decideAction(ctx) {
71
72
  reason: `Sub-issue ${issue.identifier} skipped — coordinator manages sub-issues via parent`,
72
73
  };
73
74
  }
74
- // --- Status-specific decisions ---
75
+ // --- Declarative transition routing (v1.1) ---
76
+ // When a WorkflowRegistry is present, delegate to the transition engine
77
+ // for status→phase routing. This reads from the WorkflowDefinition YAML
78
+ // instead of the hard-coded switch statement below.
79
+ //
80
+ // Icebox is excluded: top-of-funnel heuristics (description quality, delay
81
+ // thresholds, label checks) are too nuanced for simple status→phase mapping
82
+ // and remain in the dedicated decideIcebox() path until Phase 3 conditions
83
+ // can express them declaratively.
84
+ if (ctx.workflowRegistry && issue.status !== 'Icebox') {
85
+ // "Started" is a no-op in the current workflow — agent is already working.
86
+ if (issue.status === 'Started') {
87
+ return { action: 'none', reason: `Issue ${issue.identifier} is in Started status (agent already working)` };
88
+ }
89
+ // Check governor enable flags before delegating to the transition engine.
90
+ // These are configuration guards, not workflow graph concerns.
91
+ const enableCheck = checkEnableFlag(issue.status, config, issue.identifier);
92
+ if (enableCheck)
93
+ return enableCheck;
94
+ const result = evaluateTransitions({
95
+ issue,
96
+ registry: ctx.workflowRegistry,
97
+ workflowStrategy: ctx.workflowStrategy,
98
+ isParentIssue: ctx.isParentIssue,
99
+ });
100
+ return result;
101
+ }
102
+ // --- Fallback: hard-coded status-specific decisions ---
103
+ // Used when no WorkflowRegistry is available (backward compatibility).
75
104
  switch (issue.status) {
76
105
  case 'Icebox':
77
106
  return decideIcebox(ctx);
@@ -90,6 +119,35 @@ export function decideAction(ctx) {
90
119
  }
91
120
  }
92
121
  // ---------------------------------------------------------------------------
122
+ // Enable-flag guard (shared between declarative and legacy paths)
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Check whether the governor enable flag for a given status allows dispatch.
126
+ * Returns a DecisionResult to skip if disabled, or null to proceed.
127
+ */
128
+ function checkEnableFlag(status, config, issueIdentifier) {
129
+ switch (status) {
130
+ case 'Backlog':
131
+ if (!config.enableAutoDevelopment) {
132
+ return { action: 'none', reason: `Auto-development is disabled for ${issueIdentifier}` };
133
+ }
134
+ break;
135
+ case 'Finished':
136
+ if (!config.enableAutoQA) {
137
+ return { action: 'none', reason: `Auto-QA is disabled for ${issueIdentifier}` };
138
+ }
139
+ break;
140
+ case 'Delivered':
141
+ if (!config.enableAutoAcceptance) {
142
+ return { action: 'none', reason: `Auto-acceptance is disabled for ${issueIdentifier}` };
143
+ }
144
+ break;
145
+ // Rejected has no enable flag — refinement always triggers.
146
+ // Icebox is handled separately via top-of-funnel.
147
+ }
148
+ return null;
149
+ }
150
+ // ---------------------------------------------------------------------------
93
151
  // Per-status decision helpers
94
152
  // ---------------------------------------------------------------------------
95
153
  /**
@@ -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;AAMrB;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAW1D;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
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
  /**
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import type { GovernorAction, GovernorConfig, GovernorIssue, ScanResult } from './governor-types.js';
12
12
  import type { OverridePriority } from './override-parser.js';
13
+ import { type WorkflowRegistryConfig } from '../workflow/workflow-registry.js';
13
14
  /**
14
15
  * Abstract dependencies that the Governor needs to interact with
15
16
  * external systems. Callers inject these at construction time.
@@ -53,10 +54,13 @@ export declare class WorkflowGovernor {
53
54
  private readonly config;
54
55
  private readonly deps;
55
56
  private readonly callbacks;
57
+ private readonly workflowRegistry;
56
58
  private intervalHandle;
57
59
  private running;
58
60
  private scanning;
59
- constructor(config: Partial<GovernorConfig>, deps: GovernorDependencies, callbacks?: WorkflowGovernorCallbacks);
61
+ constructor(config: Partial<GovernorConfig> & {
62
+ workflow?: WorkflowRegistryConfig;
63
+ }, deps: GovernorDependencies, callbacks?: WorkflowGovernorCallbacks);
60
64
  /**
61
65
  * Start the scan loop. Runs `scanOnce()` immediately, then repeats
62
66
  * on the configured interval.
@@ -1 +1 @@
1
- {"version":3,"file":"governor.d.ts","sourceRoot":"","sources":["../../../src/governor/governor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACX,MAAM,qBAAqB,CAAA;AAG5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAsC5D;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC,CAAA;IACzD,oDAAoD;IACpD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,kEAAkE;IAClE,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,qDAAqD;IACrD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACpD,mDAAmD;IACnD,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,mEAAmE;IACnE,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC1E,wDAAwD;IACxD,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrE,kEAAkE;IAClE,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,0EAA0E;IAC1E,0BAA0B,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACjE,wEAAwE;IACxE,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9D,wDAAwD;IACxD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9E;AAMD;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACjE;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,SAAS,CAAC,EAAE,yBAAyB;IAU9G;;;OAGG;IACH,KAAK,IAAI,IAAI;IAuBb;;;OAGG;IACH,IAAI,IAAI,IAAI;IAgBZ;;OAEG;IACH,SAAS,IAAI,OAAO;IAQpB;;;;;;;;;;OAUG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA4BvC;;;;;;;OAOG;YACW,WAAW;IA2GzB;;OAEG;YACW,aAAa;CAqC5B"}
1
+ {"version":3,"file":"governor.d.ts","sourceRoot":"","sources":["../../../src/governor/governor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACX,MAAM,qBAAqB,CAAA;AAG5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAoB,KAAK,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AAsChG;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,EAAE,CAAC,CAAA;IACzD,oDAAoD;IACpD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,kEAAkE;IAClE,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,qDAAqD;IACrD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACpD,mDAAmD;IACnD,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7C,mEAAmE;IACnE,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAC1E,wDAAwD;IACxD,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACrE,kEAAkE;IAClE,mBAAmB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,0EAA0E;IAC1E,0BAA0B,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACjE,wEAAwE;IACxE,wBAAwB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9D,wDAAwD;IACxD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC9E;AAMD;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACjE;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,QAAQ,CAAQ;gBAGtB,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,sBAAsB,CAAA;KAAE,EACvE,IAAI,EAAE,oBAAoB,EAC1B,SAAS,CAAC,EAAE,yBAAyB;IAavC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAuBb;;;OAGG;IACH,IAAI,IAAI,IAAI;IAgBZ;;OAEG;IACH,SAAS,IAAI,OAAO;IAQpB;;;;;;;;;;OAUG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA4BvC;;;;;;;OAOG;YACW,WAAW;IA2GzB;;OAEG;YACW,aAAa;CAsC5B"}
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { DEFAULT_GOVERNOR_CONFIG } from './governor-types.js';
12
12
  import { decideAction } from './decision-engine.js';
13
+ import { WorkflowRegistry } from '../workflow/workflow-registry.js';
13
14
  // ---------------------------------------------------------------------------
14
15
  // Logging
15
16
  // ---------------------------------------------------------------------------
@@ -39,13 +40,16 @@ export class WorkflowGovernor {
39
40
  config;
40
41
  deps;
41
42
  callbacks;
43
+ workflowRegistry;
42
44
  intervalHandle = null;
43
45
  running = false;
44
46
  scanning = false;
45
47
  constructor(config, deps, callbacks) {
46
- this.config = { ...DEFAULT_GOVERNOR_CONFIG, ...config };
48
+ const { workflow: workflowConfig, ...governorConfig } = config;
49
+ this.config = { ...DEFAULT_GOVERNOR_CONFIG, ...governorConfig };
47
50
  this.deps = deps;
48
51
  this.callbacks = callbacks ?? {};
52
+ this.workflowRegistry = WorkflowRegistry.create(workflowConfig);
49
53
  }
50
54
  // -------------------------------------------------------------------------
51
55
  // Lifecycle
@@ -255,6 +259,7 @@ export class WorkflowGovernor {
255
259
  workflowStrategy,
256
260
  researchCompleted,
257
261
  backlogCreationCompleted,
262
+ workflowRegistry: this.workflowRegistry,
258
263
  completedSessionCount,
259
264
  };
260
265
  return decideAction(ctx);
@@ -8,4 +8,5 @@ export * from './frontend/index.js';
8
8
  export * from './config/index.js';
9
9
  export * from './manifest/index.js';
10
10
  export * from './tools/index.js';
11
+ export * from './workflow/index.js';
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAA;AACvC,cAAc,sBAAsB,CAAA;AACpC,cAAc,aAAa,CAAA;AAC3B,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA"}
package/dist/src/index.js CHANGED
@@ -8,3 +8,4 @@ export * from './frontend/index.js';
8
8
  export * from './config/index.js';
9
9
  export * from './manifest/index.js';
10
10
  export * from './tools/index.js';
11
+ export * from './workflow/index.js';
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=github-native.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-native.test.d.ts","sourceRoot":"","sources":["../../../../src/merge-queue/adapters/github-native.test.ts"],"names":[],"mappings":""}