@renseiai/agentfactory 0.8.18 → 0.8.20
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 +7 -0
- package/dist/src/config/repository-config.d.ts.map +1 -1
- package/dist/src/config/repository-config.js +15 -1
- package/dist/src/config/repository-config.test.js +1 -1
- package/dist/src/governor/decision-engine-adapter.d.ts +43 -0
- package/dist/src/governor/decision-engine-adapter.d.ts.map +1 -0
- package/dist/src/governor/decision-engine-adapter.js +417 -0
- package/dist/src/governor/decision-engine-adapter.test.d.ts +2 -0
- package/dist/src/governor/decision-engine-adapter.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine-adapter.test.js +362 -0
- package/dist/src/governor/decision-engine.js +3 -7
- package/dist/src/governor/decision-engine.test.js +5 -5
- package/dist/src/governor/index.d.ts +1 -0
- package/dist/src/governor/index.d.ts.map +1 -1
- package/dist/src/governor/index.js +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -1
- package/dist/src/manifest/route-manifest.js +4 -0
- package/dist/src/merge-queue/adapters/local.d.ts +68 -0
- package/dist/src/merge-queue/adapters/local.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/local.js +136 -0
- package/dist/src/merge-queue/adapters/local.test.d.ts +2 -0
- package/dist/src/merge-queue/adapters/local.test.d.ts.map +1 -0
- package/dist/src/merge-queue/adapters/local.test.js +176 -0
- package/dist/src/merge-queue/index.d.ts +13 -5
- package/dist/src/merge-queue/index.d.ts.map +1 -1
- package/dist/src/merge-queue/index.js +13 -6
- package/dist/src/merge-queue/merge-queue.integration.test.js +19 -0
- package/dist/src/merge-queue/merge-worker.d.ts.map +1 -1
- package/dist/src/merge-queue/merge-worker.js +29 -0
- package/dist/src/merge-queue/types.d.ts +1 -1
- package/dist/src/merge-queue/types.d.ts.map +1 -1
- package/dist/src/orchestrator/index.d.ts +4 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +3 -0
- package/dist/src/orchestrator/orchestrator.d.ts +58 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/src/orchestrator/orchestrator.js +552 -97
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -1
- package/dist/src/orchestrator/parse-work-result.js +3 -1
- package/dist/src/orchestrator/parse-work-result.test.js +6 -0
- package/dist/src/orchestrator/quality-baseline.d.ts +83 -0
- package/dist/src/orchestrator/quality-baseline.d.ts.map +1 -0
- package/dist/src/orchestrator/quality-baseline.js +313 -0
- package/dist/src/orchestrator/quality-baseline.test.d.ts +2 -0
- package/dist/src/orchestrator/quality-baseline.test.d.ts.map +1 -0
- package/dist/src/orchestrator/quality-baseline.test.js +448 -0
- package/dist/src/orchestrator/quality-ratchet.d.ts +70 -0
- package/dist/src/orchestrator/quality-ratchet.d.ts.map +1 -0
- package/dist/src/orchestrator/quality-ratchet.js +162 -0
- package/dist/src/orchestrator/quality-ratchet.test.d.ts +2 -0
- package/dist/src/orchestrator/quality-ratchet.test.d.ts.map +1 -0
- package/dist/src/orchestrator/quality-ratchet.test.js +335 -0
- package/dist/src/orchestrator/types.d.ts +2 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -1
- package/dist/src/providers/claude-provider.d.ts.map +1 -1
- package/dist/src/providers/claude-provider.js +11 -0
- package/dist/src/providers/codex-app-server-provider.d.ts +237 -0
- package/dist/src/providers/codex-app-server-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-app-server-provider.js +1041 -0
- package/dist/src/providers/codex-app-server-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-app-server-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-app-server-provider.test.js +589 -0
- package/dist/src/providers/codex-approval-bridge.d.ts +49 -0
- package/dist/src/providers/codex-approval-bridge.d.ts.map +1 -0
- package/dist/src/providers/codex-approval-bridge.js +117 -0
- package/dist/src/providers/codex-approval-bridge.test.d.ts +2 -0
- package/dist/src/providers/codex-approval-bridge.test.d.ts.map +1 -0
- package/dist/src/providers/codex-approval-bridge.test.js +188 -0
- package/dist/src/providers/codex-provider.d.ts +24 -4
- package/dist/src/providers/codex-provider.d.ts.map +1 -1
- package/dist/src/providers/codex-provider.js +58 -6
- package/dist/src/providers/index.d.ts +1 -0
- package/dist/src/providers/index.d.ts.map +1 -1
- package/dist/src/providers/index.js +1 -0
- package/dist/src/providers/types.d.ts +25 -0
- package/dist/src/providers/types.d.ts.map +1 -1
- package/dist/src/routing/observation-recorder.test.js +1 -1
- package/dist/src/routing/observation-store.d.ts +15 -1
- package/dist/src/routing/observation-store.d.ts.map +1 -1
- package/dist/src/routing/observation-store.test.js +17 -11
- package/dist/src/routing/types.d.ts +1 -1
- package/dist/src/templates/adapters.d.ts +25 -0
- package/dist/src/templates/adapters.d.ts.map +1 -1
- package/dist/src/templates/adapters.js +70 -0
- package/dist/src/templates/adapters.test.js +49 -0
- package/dist/src/templates/index.d.ts +3 -1
- package/dist/src/templates/index.d.ts.map +1 -1
- package/dist/src/templates/index.js +1 -0
- package/dist/src/templates/registry.d.ts +31 -0
- package/dist/src/templates/registry.d.ts.map +1 -1
- package/dist/src/templates/registry.js +91 -0
- package/dist/src/templates/schema.d.ts +31 -0
- package/dist/src/templates/schema.d.ts.map +1 -0
- package/dist/src/templates/schema.js +139 -0
- package/dist/src/templates/schema.test.d.ts +2 -0
- package/dist/src/templates/schema.test.d.ts.map +1 -0
- package/dist/src/templates/schema.test.js +215 -0
- package/dist/src/templates/types.d.ts +22 -0
- package/dist/src/templates/types.d.ts.map +1 -1
- package/dist/src/templates/types.js +12 -0
- package/dist/src/tools/index.d.ts +2 -0
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +1 -0
- package/dist/src/tools/registry.d.ts +9 -1
- package/dist/src/tools/registry.d.ts.map +1 -1
- package/dist/src/tools/registry.js +13 -1
- package/dist/src/tools/stdio-server-entry.d.ts +25 -0
- package/dist/src/tools/stdio-server-entry.d.ts.map +1 -0
- package/dist/src/tools/stdio-server-entry.js +205 -0
- package/dist/src/tools/stdio-server.d.ts +87 -0
- package/dist/src/tools/stdio-server.d.ts.map +1 -0
- package/dist/src/tools/stdio-server.js +138 -0
- package/dist/src/workflow/workflow-types.d.ts +3 -3
- package/package.json +3 -2
|
@@ -121,6 +121,7 @@ export declare const RepositoryConfigSchema: z.ZodObject<{
|
|
|
121
121
|
mergeQueue: z.ZodOptional<z.ZodObject<{
|
|
122
122
|
provider: z.ZodDefault<z.ZodEnum<{
|
|
123
123
|
"github-native": "github-native";
|
|
124
|
+
local: "local";
|
|
124
125
|
mergify: "mergify";
|
|
125
126
|
trunk: "trunk";
|
|
126
127
|
}>>;
|
|
@@ -159,6 +160,12 @@ export declare const RepositoryConfigSchema: z.ZodObject<{
|
|
|
159
160
|
default: "default";
|
|
160
161
|
mergiraf: "mergiraf";
|
|
161
162
|
}>>;
|
|
163
|
+
quality: z.ZodOptional<z.ZodObject<{
|
|
164
|
+
baselineEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
165
|
+
ratchetEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
166
|
+
boyscoutRule: z.ZodDefault<z.ZodBoolean>;
|
|
167
|
+
tddWorkflow: z.ZodDefault<z.ZodBoolean>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
162
169
|
}, z.core.$strip>;
|
|
163
170
|
export type RepositoryConfig = z.infer<typeof RepositoryConfigSchema>;
|
|
164
171
|
/**
|
|
@@ -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;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMxD,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,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;iBAarC,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;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAMxD,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,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B;;;;;;;iBAarC,CAAA;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4HlC,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;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,aAAa,GAAG,SAAS,CAEpF;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ7E"}
|
|
@@ -116,7 +116,7 @@ export const RepositoryConfigSchema = z.object({
|
|
|
116
116
|
*/
|
|
117
117
|
mergeQueue: z.object({
|
|
118
118
|
/** Merge queue provider to use */
|
|
119
|
-
provider: z.enum(['github-native', 'mergify', 'trunk']).default('
|
|
119
|
+
provider: z.enum(['github-native', 'local', 'mergify', 'trunk']).default('local'),
|
|
120
120
|
/** Whether merge queue integration is enabled */
|
|
121
121
|
enabled: z.boolean().default(false),
|
|
122
122
|
/** Automatically add approved PRs to merge queue */
|
|
@@ -164,6 +164,20 @@ export const RepositoryConfigSchema = z.object({
|
|
|
164
164
|
* Defaults to 'default' (standard git line-based merge).
|
|
165
165
|
*/
|
|
166
166
|
mergeDriver: z.enum(['mergiraf', 'default']).optional(),
|
|
167
|
+
/**
|
|
168
|
+
* Quality gate configuration.
|
|
169
|
+
* Controls baseline-diff quality checks and ratchet enforcement.
|
|
170
|
+
*/
|
|
171
|
+
quality: z.object({
|
|
172
|
+
/** Enable quality baseline capture at worktree creation and post-session delta check */
|
|
173
|
+
baselineEnabled: z.boolean().default(false),
|
|
174
|
+
/** Enable quality ratchet enforcement in merge queue and CI */
|
|
175
|
+
ratchetEnabled: z.boolean().default(false),
|
|
176
|
+
/** Include boy scout rule instructions in agent prompts */
|
|
177
|
+
boyscoutRule: z.boolean().default(true),
|
|
178
|
+
/** Include TDD workflow instructions in agent prompts */
|
|
179
|
+
tddWorkflow: z.boolean().default(true),
|
|
180
|
+
}).optional(),
|
|
167
181
|
}).refine((data) => !(data.allowedProjects && data.projectPaths), { message: 'allowedProjects and projectPaths are mutually exclusive — use one or the other' });
|
|
168
182
|
// ---------------------------------------------------------------------------
|
|
169
183
|
// Helpers
|
|
@@ -695,7 +695,7 @@ describe('RepositoryConfigSchema mergeQueue — Refinery fields', () => {
|
|
|
695
695
|
mergeQueue: { enabled: true },
|
|
696
696
|
});
|
|
697
697
|
expect(result.mergeQueue).toBeDefined();
|
|
698
|
-
expect(result.mergeQueue.provider).toBe('
|
|
698
|
+
expect(result.mergeQueue.provider).toBe('local');
|
|
699
699
|
expect(result.mergeQueue.enabled).toBe(true);
|
|
700
700
|
expect(result.mergeQueue.autoMerge).toBe(true);
|
|
701
701
|
expect(result.mergeQueue.requiredChecks).toBeUndefined();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision Engine Adapter
|
|
3
|
+
*
|
|
4
|
+
* Translates the full `decideAction()` decision context into a
|
|
5
|
+
* WorkflowDefinition v2 YAML equivalent. Each decision point in the
|
|
6
|
+
* engine becomes a condition node or action node in the v2 graph.
|
|
7
|
+
*
|
|
8
|
+
* This adapter enables the platform to replace the legacy decision engine
|
|
9
|
+
* with a declarative workflow while preserving identical behavior.
|
|
10
|
+
*
|
|
11
|
+
* @see SUP-1757
|
|
12
|
+
*/
|
|
13
|
+
import type { GovernorConfig } from './governor-types.js';
|
|
14
|
+
import type { WorkflowDefinitionV2 } from '../workflow/workflow-types.js';
|
|
15
|
+
export interface DecisionEngineAdapterConfig {
|
|
16
|
+
/** Governor configuration to derive workflow from */
|
|
17
|
+
governorConfig?: GovernorConfig;
|
|
18
|
+
/** Workflow name (default: "governor-decision-engine") */
|
|
19
|
+
workflowName?: string;
|
|
20
|
+
/** Whether to include top-of-funnel nodes (Icebox handling) */
|
|
21
|
+
includeTopOfFunnel?: boolean;
|
|
22
|
+
/** Whether to include merge queue handling */
|
|
23
|
+
includeMergeQueue?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Converts the Governor's `decideAction()` logic into a WorkflowDefinition v2.
|
|
27
|
+
*
|
|
28
|
+
* The generated workflow mirrors the decision tree exactly:
|
|
29
|
+
*
|
|
30
|
+
* 1. Universal guards: active-session, cooldown, hold, gates, circuit-breaker
|
|
31
|
+
* 2. Terminal statuses: Accepted, Canceled, Duplicate
|
|
32
|
+
* 3. Sub-issue guard
|
|
33
|
+
* 4. Status-specific routing: Icebox, Backlog, Started, Finished, Delivered, Rejected
|
|
34
|
+
* 5. Escalation strategy overrides (decompose, escalate-human)
|
|
35
|
+
* 6. Merge queue handling
|
|
36
|
+
*/
|
|
37
|
+
export declare class DecisionEngineAdapter {
|
|
38
|
+
/**
|
|
39
|
+
* Generate a WorkflowDefinition v2 that replicates the full decision engine.
|
|
40
|
+
*/
|
|
41
|
+
static toWorkflowDefinition(config?: DecisionEngineAdapterConfig): WorkflowDefinitionV2;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=decision-engine-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-engine-adapter.d.ts","sourceRoot":"","sources":["../../../src/governor/decision-engine-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,KAAK,EACV,oBAAoB,EAKrB,MAAM,+BAA+B,CAAA;AAOtC,MAAM,WAAW,2BAA2B;IAC1C,qDAAqD;IACrD,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAMD;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAqB;IAChC;;OAEG;IACH,MAAM,CAAC,oBAAoB,CACzB,MAAM,GAAE,2BAAgC,GACvC,oBAAoB;CAgCxB"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision Engine Adapter
|
|
3
|
+
*
|
|
4
|
+
* Translates the full `decideAction()` decision context into a
|
|
5
|
+
* WorkflowDefinition v2 YAML equivalent. Each decision point in the
|
|
6
|
+
* engine becomes a condition node or action node in the v2 graph.
|
|
7
|
+
*
|
|
8
|
+
* This adapter enables the platform to replace the legacy decision engine
|
|
9
|
+
* with a declarative workflow while preserving identical behavior.
|
|
10
|
+
*
|
|
11
|
+
* @see SUP-1757
|
|
12
|
+
*/
|
|
13
|
+
import { DEFAULT_GOVERNOR_CONFIG } from './governor-types.js';
|
|
14
|
+
import { MAX_SESSION_ATTEMPTS } from './decision-engine.js';
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Adapter
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Converts the Governor's `decideAction()` logic into a WorkflowDefinition v2.
|
|
20
|
+
*
|
|
21
|
+
* The generated workflow mirrors the decision tree exactly:
|
|
22
|
+
*
|
|
23
|
+
* 1. Universal guards: active-session, cooldown, hold, gates, circuit-breaker
|
|
24
|
+
* 2. Terminal statuses: Accepted, Canceled, Duplicate
|
|
25
|
+
* 3. Sub-issue guard
|
|
26
|
+
* 4. Status-specific routing: Icebox, Backlog, Started, Finished, Delivered, Rejected
|
|
27
|
+
* 5. Escalation strategy overrides (decompose, escalate-human)
|
|
28
|
+
* 6. Merge queue handling
|
|
29
|
+
*/
|
|
30
|
+
export class DecisionEngineAdapter {
|
|
31
|
+
/**
|
|
32
|
+
* Generate a WorkflowDefinition v2 that replicates the full decision engine.
|
|
33
|
+
*/
|
|
34
|
+
static toWorkflowDefinition(config = {}) {
|
|
35
|
+
const govConfig = config.governorConfig ?? DEFAULT_GOVERNOR_CONFIG;
|
|
36
|
+
const workflowName = config.workflowName ?? 'governor-decision-engine';
|
|
37
|
+
const includeTopOfFunnel = config.includeTopOfFunnel ?? true;
|
|
38
|
+
const includeMergeQueue = config.includeMergeQueue ?? false;
|
|
39
|
+
const triggers = buildTriggers();
|
|
40
|
+
const providers = buildProviders();
|
|
41
|
+
const nodes = buildNodes(govConfig, includeTopOfFunnel, includeMergeQueue);
|
|
42
|
+
return {
|
|
43
|
+
apiVersion: 'v2',
|
|
44
|
+
kind: 'WorkflowDefinition',
|
|
45
|
+
metadata: {
|
|
46
|
+
name: workflowName,
|
|
47
|
+
description: 'Auto-generated from Governor DecisionEngine. ' +
|
|
48
|
+
'Replicates the full decideAction() decision tree as v2 workflow nodes.',
|
|
49
|
+
},
|
|
50
|
+
triggers,
|
|
51
|
+
providers,
|
|
52
|
+
config: {
|
|
53
|
+
maxSessionAttempts: MAX_SESSION_ATTEMPTS,
|
|
54
|
+
enableAutoDevelopment: govConfig.enableAutoDevelopment,
|
|
55
|
+
enableAutoQA: govConfig.enableAutoQA,
|
|
56
|
+
enableAutoAcceptance: govConfig.enableAutoAcceptance,
|
|
57
|
+
enableAutoResearch: govConfig.enableAutoResearch,
|
|
58
|
+
enableAutoBacklogCreation: govConfig.enableAutoBacklogCreation,
|
|
59
|
+
},
|
|
60
|
+
nodes,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Trigger builders
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
function buildTriggers() {
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
name: 'issue-status-change',
|
|
71
|
+
type: 'webhook',
|
|
72
|
+
source: 'linear',
|
|
73
|
+
event: 'issue.status_changed',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'governor-scan',
|
|
77
|
+
type: 'schedule',
|
|
78
|
+
schedule: '*/1 * * * *', // Every minute
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Provider builders
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
function buildProviders() {
|
|
86
|
+
return [
|
|
87
|
+
{ name: 'linear', type: 'linear' },
|
|
88
|
+
{ name: 'agent', type: 'agent-provider' },
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Node builders
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
function buildNodes(config, includeTopOfFunnel, includeMergeQueue) {
|
|
95
|
+
const nodes = [];
|
|
96
|
+
// --- Universal guard nodes ---
|
|
97
|
+
nodes.push(buildActiveSessionGuard());
|
|
98
|
+
nodes.push(buildCooldownGuard());
|
|
99
|
+
nodes.push(buildHoldGuard());
|
|
100
|
+
nodes.push(buildGateGuard());
|
|
101
|
+
nodes.push(buildCircuitBreakerGuard());
|
|
102
|
+
nodes.push(buildTerminalStatusGuard());
|
|
103
|
+
nodes.push(buildSubIssueGuard());
|
|
104
|
+
// --- Status-specific routing nodes ---
|
|
105
|
+
if (includeTopOfFunnel) {
|
|
106
|
+
nodes.push(buildIceboxResearchNode(config));
|
|
107
|
+
nodes.push(buildIceboxBacklogCreationNode(config));
|
|
108
|
+
}
|
|
109
|
+
nodes.push(buildBacklogNode(config));
|
|
110
|
+
nodes.push(buildStartedNode());
|
|
111
|
+
nodes.push(buildFinishedNode(config, includeMergeQueue));
|
|
112
|
+
nodes.push(buildDeliveredNode(config));
|
|
113
|
+
nodes.push(buildRejectedNode());
|
|
114
|
+
return nodes;
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Guard nodes
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
function buildActiveSessionGuard() {
|
|
120
|
+
return {
|
|
121
|
+
name: 'guard-active-session',
|
|
122
|
+
description: 'Skip if issue already has an active agent session',
|
|
123
|
+
when: '{{ hasActiveSession }}',
|
|
124
|
+
steps: [
|
|
125
|
+
{
|
|
126
|
+
id: 'skip',
|
|
127
|
+
action: 'none',
|
|
128
|
+
with: {
|
|
129
|
+
reason: 'Issue {{ issue.identifier }} already has an active agent session',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function buildCooldownGuard() {
|
|
136
|
+
return {
|
|
137
|
+
name: 'guard-cooldown',
|
|
138
|
+
description: 'Skip if issue is within cooldown period',
|
|
139
|
+
when: '{{ isWithinCooldown }}',
|
|
140
|
+
steps: [
|
|
141
|
+
{
|
|
142
|
+
id: 'skip',
|
|
143
|
+
action: 'none',
|
|
144
|
+
with: {
|
|
145
|
+
reason: 'Issue {{ issue.identifier }} is within cooldown period',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function buildHoldGuard() {
|
|
152
|
+
return {
|
|
153
|
+
name: 'guard-hold',
|
|
154
|
+
description: 'Skip if HOLD override is active',
|
|
155
|
+
when: '{{ isHeld }}',
|
|
156
|
+
steps: [
|
|
157
|
+
{
|
|
158
|
+
id: 'skip',
|
|
159
|
+
action: 'none',
|
|
160
|
+
with: {
|
|
161
|
+
reason: 'Issue {{ issue.identifier }} is held (HOLD override active)',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function buildGateGuard() {
|
|
168
|
+
return {
|
|
169
|
+
name: 'guard-gates',
|
|
170
|
+
description: 'Block when gates are unsatisfied (Phase 4 gate evaluation)',
|
|
171
|
+
when: '{{ gateEvaluation && !gateEvaluation.allSatisfied }}',
|
|
172
|
+
steps: [
|
|
173
|
+
{
|
|
174
|
+
id: 'block',
|
|
175
|
+
action: 'none',
|
|
176
|
+
with: {
|
|
177
|
+
reason: 'Issue {{ issue.identifier }} has unsatisfied gates',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function buildCircuitBreakerGuard() {
|
|
184
|
+
return {
|
|
185
|
+
name: 'guard-circuit-breaker',
|
|
186
|
+
description: `Trip circuit breaker when session count >= ${MAX_SESSION_ATTEMPTS}`,
|
|
187
|
+
when: `{{ completedSessionCount >= ${MAX_SESSION_ATTEMPTS} }}`,
|
|
188
|
+
steps: [
|
|
189
|
+
{
|
|
190
|
+
id: 'trip',
|
|
191
|
+
action: 'none',
|
|
192
|
+
with: {
|
|
193
|
+
reason: `Issue {{ issue.identifier }} has had {{ completedSessionCount }} agent sessions — circuit breaker tripped (max ${MAX_SESSION_ATTEMPTS})`,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function buildTerminalStatusGuard() {
|
|
200
|
+
return {
|
|
201
|
+
name: 'guard-terminal-status',
|
|
202
|
+
description: 'No action for terminal statuses (Accepted, Canceled, Duplicate)',
|
|
203
|
+
when: "{{ issue.status == 'Accepted' || issue.status == 'Canceled' || issue.status == 'Duplicate' }}",
|
|
204
|
+
steps: [
|
|
205
|
+
{
|
|
206
|
+
id: 'skip',
|
|
207
|
+
action: 'none',
|
|
208
|
+
with: {
|
|
209
|
+
reason: 'Issue {{ issue.identifier }} is in terminal status: {{ issue.status }}',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function buildSubIssueGuard() {
|
|
216
|
+
return {
|
|
217
|
+
name: 'guard-sub-issue',
|
|
218
|
+
description: 'Sub-issues managed by coordinator via parent — skip direct dispatch',
|
|
219
|
+
when: '{{ issue.parentId != undefined }}',
|
|
220
|
+
steps: [
|
|
221
|
+
{
|
|
222
|
+
id: 'skip',
|
|
223
|
+
action: 'none',
|
|
224
|
+
with: {
|
|
225
|
+
reason: 'Sub-issue {{ issue.identifier }} skipped — coordinator manages sub-issues via parent',
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Status-specific routing nodes
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
function buildIceboxResearchNode(config) {
|
|
235
|
+
return {
|
|
236
|
+
name: 'icebox-research',
|
|
237
|
+
description: 'Trigger research for sparse Icebox issues (top-of-funnel)',
|
|
238
|
+
provider: 'agent',
|
|
239
|
+
when: `{{ issue.status == 'Icebox' && config.enableAutoResearch && !researchCompleted && !isParentIssue }}`,
|
|
240
|
+
steps: [
|
|
241
|
+
{
|
|
242
|
+
id: 'evaluate',
|
|
243
|
+
action: 'trigger-research',
|
|
244
|
+
with: {
|
|
245
|
+
enableAutoResearch: config.enableAutoResearch,
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function buildIceboxBacklogCreationNode(config) {
|
|
252
|
+
return {
|
|
253
|
+
name: 'icebox-backlog-creation',
|
|
254
|
+
description: 'Trigger backlog creation for well-researched Icebox issues',
|
|
255
|
+
provider: 'agent',
|
|
256
|
+
when: `{{ issue.status == 'Icebox' && config.enableAutoBacklogCreation && !backlogCreationCompleted && !isParentIssue }}`,
|
|
257
|
+
steps: [
|
|
258
|
+
{
|
|
259
|
+
id: 'evaluate',
|
|
260
|
+
action: 'trigger-backlog-creation',
|
|
261
|
+
with: {
|
|
262
|
+
enableAutoBacklogCreation: config.enableAutoBacklogCreation,
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function buildBacklogNode(config) {
|
|
269
|
+
return {
|
|
270
|
+
name: 'route-backlog',
|
|
271
|
+
description: 'Backlog → trigger-development (if enabled)',
|
|
272
|
+
provider: 'agent',
|
|
273
|
+
when: "{{ issue.status == 'Backlog' }}",
|
|
274
|
+
steps: [
|
|
275
|
+
{
|
|
276
|
+
id: 'check-enabled',
|
|
277
|
+
action: 'none',
|
|
278
|
+
when: `{{ !config.enableAutoDevelopment }}`,
|
|
279
|
+
with: {
|
|
280
|
+
reason: 'Auto-development is disabled for {{ issue.identifier }}',
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'dispatch',
|
|
285
|
+
action: 'trigger-development',
|
|
286
|
+
when: `{{ config.enableAutoDevelopment }}`,
|
|
287
|
+
with: {
|
|
288
|
+
isParentIssue: '{{ isParentIssue }}',
|
|
289
|
+
reason: '{{ isParentIssue ? "Parent issue" : "Issue" }} {{ issue.identifier }} is in Backlog — triggering {{ isParentIssue ? "coordination " : "" }}development',
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function buildStartedNode() {
|
|
296
|
+
return {
|
|
297
|
+
name: 'route-started',
|
|
298
|
+
description: 'Started → none (agent already working)',
|
|
299
|
+
when: "{{ issue.status == 'Started' }}",
|
|
300
|
+
steps: [
|
|
301
|
+
{
|
|
302
|
+
id: 'skip',
|
|
303
|
+
action: 'none',
|
|
304
|
+
with: {
|
|
305
|
+
reason: 'Issue {{ issue.identifier }} is in Started status (agent already working)',
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function buildFinishedNode(config, includeMergeQueue) {
|
|
312
|
+
const steps = [
|
|
313
|
+
{
|
|
314
|
+
id: 'check-enabled',
|
|
315
|
+
action: 'none',
|
|
316
|
+
when: '{{ !config.enableAutoQA }}',
|
|
317
|
+
with: {
|
|
318
|
+
reason: 'Auto-QA is disabled for {{ issue.identifier }}',
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
id: 'check-escalate-human',
|
|
323
|
+
action: 'escalate-human',
|
|
324
|
+
when: "{{ workflowStrategy == 'escalate-human' }}",
|
|
325
|
+
with: {
|
|
326
|
+
reason: 'Issue {{ issue.identifier }} is in Finished with escalate-human strategy — needs human review',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: 'check-decompose',
|
|
331
|
+
action: 'decompose',
|
|
332
|
+
when: "{{ workflowStrategy == 'decompose' }}",
|
|
333
|
+
with: {
|
|
334
|
+
reason: 'Issue {{ issue.identifier }} is in Finished with decompose strategy — triggering decomposition',
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
];
|
|
338
|
+
// Always trigger QA for functional validation — merge queue handles git
|
|
339
|
+
// mechanics at merge time, not as a QA bypass.
|
|
340
|
+
// The includeMergeQueue flag is preserved for the adapter signature but the
|
|
341
|
+
// Finished node no longer short-circuits to trigger-merge.
|
|
342
|
+
void includeMergeQueue;
|
|
343
|
+
steps.push({
|
|
344
|
+
id: 'dispatch-qa',
|
|
345
|
+
action: 'trigger-qa',
|
|
346
|
+
when: '{{ config.enableAutoQA }}',
|
|
347
|
+
with: {
|
|
348
|
+
reason: 'Issue {{ issue.identifier }} is in Finished — triggering QA',
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
return {
|
|
352
|
+
name: 'route-finished',
|
|
353
|
+
description: 'Finished → trigger-qa (with escalation/merge-queue checks)',
|
|
354
|
+
provider: 'agent',
|
|
355
|
+
when: "{{ issue.status == 'Finished' }}",
|
|
356
|
+
steps,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
function buildDeliveredNode(config) {
|
|
360
|
+
return {
|
|
361
|
+
name: 'route-delivered',
|
|
362
|
+
description: 'Delivered → trigger-acceptance (if enabled)',
|
|
363
|
+
provider: 'agent',
|
|
364
|
+
when: "{{ issue.status == 'Delivered' }}",
|
|
365
|
+
steps: [
|
|
366
|
+
{
|
|
367
|
+
id: 'check-enabled',
|
|
368
|
+
action: 'none',
|
|
369
|
+
when: '{{ !config.enableAutoAcceptance }}',
|
|
370
|
+
with: {
|
|
371
|
+
reason: 'Auto-acceptance is disabled for {{ issue.identifier }}',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
id: 'dispatch',
|
|
376
|
+
action: 'trigger-acceptance',
|
|
377
|
+
when: '{{ config.enableAutoAcceptance }}',
|
|
378
|
+
with: {
|
|
379
|
+
reason: 'Issue {{ issue.identifier }} is in Delivered — triggering acceptance',
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
],
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function buildRejectedNode() {
|
|
386
|
+
return {
|
|
387
|
+
name: 'route-rejected',
|
|
388
|
+
description: 'Rejected → trigger-refinement (with escalation checks)',
|
|
389
|
+
provider: 'agent',
|
|
390
|
+
when: "{{ issue.status == 'Rejected' }}",
|
|
391
|
+
steps: [
|
|
392
|
+
{
|
|
393
|
+
id: 'check-escalate-human',
|
|
394
|
+
action: 'escalate-human',
|
|
395
|
+
when: "{{ workflowStrategy == 'escalate-human' }}",
|
|
396
|
+
with: {
|
|
397
|
+
reason: 'Issue {{ issue.identifier }} is Rejected with escalate-human strategy — needs human intervention',
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: 'check-decompose',
|
|
402
|
+
action: 'decompose',
|
|
403
|
+
when: "{{ workflowStrategy == 'decompose' }}",
|
|
404
|
+
with: {
|
|
405
|
+
reason: 'Issue {{ issue.identifier }} is Rejected with decompose strategy — triggering decomposition',
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: 'dispatch-refinement',
|
|
410
|
+
action: 'trigger-refinement',
|
|
411
|
+
with: {
|
|
412
|
+
reason: 'Issue {{ issue.identifier }} is Rejected — triggering refinement',
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
};
|
|
417
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-engine-adapter.test.d.ts","sourceRoot":"","sources":["../../../src/governor/decision-engine-adapter.test.ts"],"names":[],"mappings":""}
|