@renseiai/agentfactory 0.8.0
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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/repository-config.d.ts +44 -0
- package/dist/src/config/repository-config.d.ts.map +1 -0
- package/dist/src/config/repository-config.js +88 -0
- package/dist/src/config/repository-config.test.d.ts +2 -0
- package/dist/src/config/repository-config.test.d.ts.map +1 -0
- package/dist/src/config/repository-config.test.js +249 -0
- package/dist/src/deployment/deployment-checker.d.ts +110 -0
- package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
- package/dist/src/deployment/deployment-checker.js +242 -0
- package/dist/src/deployment/index.d.ts +3 -0
- package/dist/src/deployment/index.d.ts.map +1 -0
- package/dist/src/deployment/index.js +2 -0
- package/dist/src/frontend/index.d.ts +2 -0
- package/dist/src/frontend/index.d.ts.map +1 -0
- package/dist/src/frontend/index.js +1 -0
- package/dist/src/frontend/types.d.ts +106 -0
- package/dist/src/frontend/types.d.ts.map +1 -0
- package/dist/src/frontend/types.js +11 -0
- package/dist/src/governor/decision-engine.d.ts +52 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.js +220 -0
- package/dist/src/governor/decision-engine.test.d.ts +2 -0
- package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.test.js +629 -0
- package/dist/src/governor/event-bus.d.ts +43 -0
- package/dist/src/governor/event-bus.d.ts.map +1 -0
- package/dist/src/governor/event-bus.js +8 -0
- package/dist/src/governor/event-deduplicator.d.ts +43 -0
- package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
- package/dist/src/governor/event-deduplicator.js +53 -0
- package/dist/src/governor/event-driven-governor.d.ts +131 -0
- package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.js +379 -0
- package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
- package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.test.js +673 -0
- package/dist/src/governor/event-types.d.ts +78 -0
- package/dist/src/governor/event-types.d.ts.map +1 -0
- package/dist/src/governor/event-types.js +32 -0
- package/dist/src/governor/governor-types.d.ts +82 -0
- package/dist/src/governor/governor-types.d.ts.map +1 -0
- package/dist/src/governor/governor-types.js +21 -0
- package/dist/src/governor/governor.d.ts +100 -0
- package/dist/src/governor/governor.d.ts.map +1 -0
- package/dist/src/governor/governor.js +262 -0
- package/dist/src/governor/governor.test.d.ts +2 -0
- package/dist/src/governor/governor.test.d.ts.map +1 -0
- package/dist/src/governor/governor.test.js +514 -0
- package/dist/src/governor/human-touchpoints.d.ts +131 -0
- package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.js +251 -0
- package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
- package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.test.js +366 -0
- package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
- package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
- package/dist/src/governor/in-memory-event-bus.js +79 -0
- package/dist/src/governor/index.d.ts +14 -0
- package/dist/src/governor/index.d.ts.map +1 -0
- package/dist/src/governor/index.js +13 -0
- package/dist/src/governor/override-parser.d.ts +60 -0
- package/dist/src/governor/override-parser.d.ts.map +1 -0
- package/dist/src/governor/override-parser.js +98 -0
- package/dist/src/governor/override-parser.test.d.ts +2 -0
- package/dist/src/governor/override-parser.test.d.ts.map +1 -0
- package/dist/src/governor/override-parser.test.js +312 -0
- package/dist/src/governor/platform-adapter.d.ts +69 -0
- package/dist/src/governor/platform-adapter.d.ts.map +1 -0
- package/dist/src/governor/platform-adapter.js +11 -0
- package/dist/src/governor/processing-state.d.ts +66 -0
- package/dist/src/governor/processing-state.d.ts.map +1 -0
- package/dist/src/governor/processing-state.js +43 -0
- package/dist/src/governor/processing-state.test.d.ts +2 -0
- package/dist/src/governor/processing-state.test.d.ts.map +1 -0
- package/dist/src/governor/processing-state.test.js +96 -0
- package/dist/src/governor/top-of-funnel.d.ts +118 -0
- package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.js +168 -0
- package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
- package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.test.js +331 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/linear-cli.d.ts +38 -0
- package/dist/src/linear-cli.d.ts.map +1 -0
- package/dist/src/linear-cli.js +674 -0
- package/dist/src/logger.d.ts +117 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +430 -0
- package/dist/src/manifest/generate.d.ts +20 -0
- package/dist/src/manifest/generate.d.ts.map +1 -0
- package/dist/src/manifest/generate.js +65 -0
- package/dist/src/manifest/index.d.ts +4 -0
- package/dist/src/manifest/index.d.ts.map +1 -0
- package/dist/src/manifest/index.js +2 -0
- package/dist/src/manifest/route-manifest.d.ts +34 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -0
- package/dist/src/manifest/route-manifest.js +148 -0
- package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
- package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/activity-emitter.js +306 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/api-activity-emitter.js +417 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
- package/dist/src/orchestrator/heartbeat-writer.js +137 -0
- package/dist/src/orchestrator/index.d.ts +20 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +22 -0
- package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
- package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
- package/dist/src/orchestrator/log-analyzer.js +572 -0
- package/dist/src/orchestrator/log-config.d.ts +39 -0
- package/dist/src/orchestrator/log-config.d.ts.map +1 -0
- package/dist/src/orchestrator/log-config.js +45 -0
- package/dist/src/orchestrator/orchestrator.d.ts +316 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/orchestrator.js +3290 -0
- package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.js +135 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.test.js +234 -0
- package/dist/src/orchestrator/progress-logger.d.ts +72 -0
- package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/progress-logger.js +135 -0
- package/dist/src/orchestrator/session-logger.d.ts +159 -0
- package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/session-logger.js +275 -0
- package/dist/src/orchestrator/state-recovery.d.ts +96 -0
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
- package/dist/src/orchestrator/state-recovery.js +302 -0
- package/dist/src/orchestrator/state-types.d.ts +165 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -0
- package/dist/src/orchestrator/state-types.js +7 -0
- package/dist/src/orchestrator/stream-parser.d.ts +151 -0
- package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
- package/dist/src/orchestrator/stream-parser.js +137 -0
- package/dist/src/orchestrator/types.d.ts +232 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +4 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
- package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
- package/dist/src/providers/a2a-auth.d.ts +81 -0
- package/dist/src/providers/a2a-auth.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.js +188 -0
- package/dist/src/providers/a2a-auth.test.d.ts +2 -0
- package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.test.js +232 -0
- package/dist/src/providers/a2a-provider.d.ts +254 -0
- package/dist/src/providers/a2a-provider.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.js +665 -0
- package/dist/src/providers/a2a-provider.js +811 -0
- package/dist/src/providers/a2a-provider.test.d.ts +2 -0
- package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.test.js +681 -0
- package/dist/src/providers/amp-provider.d.ts +20 -0
- package/dist/src/providers/amp-provider.d.ts.map +1 -0
- package/dist/src/providers/amp-provider.js +24 -0
- package/dist/src/providers/claude-provider.d.ts +18 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -0
- package/dist/src/providers/claude-provider.js +437 -0
- package/dist/src/providers/codex-provider.d.ts +133 -0
- package/dist/src/providers/codex-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.js +381 -0
- package/dist/src/providers/codex-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.test.js +387 -0
- package/dist/src/providers/index.d.ts +44 -0
- package/dist/src/providers/index.d.ts.map +1 -0
- package/dist/src/providers/index.js +85 -0
- package/dist/src/providers/spring-ai-provider.d.ts +90 -0
- package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
- package/dist/src/providers/spring-ai-provider.js +317 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.test.js +200 -0
- package/dist/src/providers/types.d.ts +165 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +13 -0
- package/dist/src/templates/adapters.d.ts +51 -0
- package/dist/src/templates/adapters.d.ts.map +1 -0
- package/dist/src/templates/adapters.js +104 -0
- package/dist/src/templates/adapters.test.d.ts +2 -0
- package/dist/src/templates/adapters.test.d.ts.map +1 -0
- package/dist/src/templates/adapters.test.js +165 -0
- package/dist/src/templates/agent-definition.d.ts +85 -0
- package/dist/src/templates/agent-definition.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.js +97 -0
- package/dist/src/templates/agent-definition.test.d.ts +2 -0
- package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.test.js +209 -0
- package/dist/src/templates/index.d.ts +14 -0
- package/dist/src/templates/index.d.ts.map +1 -0
- package/dist/src/templates/index.js +11 -0
- package/dist/src/templates/loader.d.ts +41 -0
- package/dist/src/templates/loader.d.ts.map +1 -0
- package/dist/src/templates/loader.js +114 -0
- package/dist/src/templates/registry.d.ts +80 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +177 -0
- package/dist/src/templates/registry.test.d.ts +2 -0
- package/dist/src/templates/registry.test.d.ts.map +1 -0
- package/dist/src/templates/registry.test.js +198 -0
- package/dist/src/templates/renderer.d.ts +29 -0
- package/dist/src/templates/renderer.d.ts.map +1 -0
- package/dist/src/templates/renderer.js +35 -0
- package/dist/src/templates/strategy-templates.test.d.ts +2 -0
- package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
- package/dist/src/templates/strategy-templates.test.js +619 -0
- package/dist/src/templates/types.d.ts +233 -0
- package/dist/src/templates/types.d.ts.map +1 -0
- package/dist/src/templates/types.js +127 -0
- package/dist/src/templates/types.test.d.ts +2 -0
- package/dist/src/templates/types.test.d.ts.map +1 -0
- package/dist/src/templates/types.test.js +232 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/linear-runner.d.ts +34 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +700 -0
- package/dist/src/tools/plugins/linear.d.ts +9 -0
- package/dist/src/tools/plugins/linear.d.ts.map +1 -0
- package/dist/src/tools/plugins/linear.js +138 -0
- package/dist/src/tools/registry.d.ts +9 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +18 -0
- package/dist/src/tools/types.d.ts +18 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governor Event Types
|
|
3
|
+
*
|
|
4
|
+
* Discriminated union of events that flow through the GovernorEventBus.
|
|
5
|
+
* Events are produced by webhooks (real-time) and poll sweeps (periodic),
|
|
6
|
+
* then consumed by the EventDrivenGovernor for decision-making.
|
|
7
|
+
*/
|
|
8
|
+
import type { GovernorIssue } from './governor-types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Fired when an issue's workflow status changes (e.g., Backlog → Started).
|
|
11
|
+
* Typically produced by webhook `issue-updated` or a poll sweep diff.
|
|
12
|
+
*/
|
|
13
|
+
export interface IssueStatusChangedEvent {
|
|
14
|
+
type: 'issue-status-changed';
|
|
15
|
+
issueId: string;
|
|
16
|
+
issue: GovernorIssue;
|
|
17
|
+
previousStatus?: string;
|
|
18
|
+
newStatus: string;
|
|
19
|
+
/** ISO-8601 timestamp */
|
|
20
|
+
timestamp: string;
|
|
21
|
+
/** Where this event originated */
|
|
22
|
+
source: EventSource;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fired when a comment is added to an issue.
|
|
26
|
+
* Used for parsing human override directives (HOLD, RESUME, PRIORITY, etc.).
|
|
27
|
+
*/
|
|
28
|
+
export interface CommentAddedEvent {
|
|
29
|
+
type: 'comment-added';
|
|
30
|
+
issueId: string;
|
|
31
|
+
issue: GovernorIssue;
|
|
32
|
+
commentId: string;
|
|
33
|
+
commentBody: string;
|
|
34
|
+
userId?: string;
|
|
35
|
+
userName?: string;
|
|
36
|
+
/** ISO-8601 timestamp */
|
|
37
|
+
timestamp: string;
|
|
38
|
+
source: EventSource;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Fired when an agent session completes (success or failure).
|
|
42
|
+
* Allows the Governor to re-evaluate the issue immediately.
|
|
43
|
+
*/
|
|
44
|
+
export interface SessionCompletedEvent {
|
|
45
|
+
type: 'session-completed';
|
|
46
|
+
issueId: string;
|
|
47
|
+
issue: GovernorIssue;
|
|
48
|
+
sessionId: string;
|
|
49
|
+
outcome: 'success' | 'failure';
|
|
50
|
+
/** ISO-8601 timestamp */
|
|
51
|
+
timestamp: string;
|
|
52
|
+
source: EventSource;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Emitted by periodic poll sweeps. Contains a full snapshot of a single
|
|
56
|
+
* issue so the Governor can evaluate it without an extra API call.
|
|
57
|
+
*/
|
|
58
|
+
export interface PollSnapshotEvent {
|
|
59
|
+
type: 'poll-snapshot';
|
|
60
|
+
issueId: string;
|
|
61
|
+
issue: GovernorIssue;
|
|
62
|
+
project: string;
|
|
63
|
+
/** ISO-8601 timestamp */
|
|
64
|
+
timestamp: string;
|
|
65
|
+
source: EventSource;
|
|
66
|
+
}
|
|
67
|
+
export type EventSource = 'webhook' | 'poll' | 'manual';
|
|
68
|
+
export type GovernorEvent = IssueStatusChangedEvent | CommentAddedEvent | SessionCompletedEvent | PollSnapshotEvent;
|
|
69
|
+
/**
|
|
70
|
+
* Generate a deduplication key for an event.
|
|
71
|
+
* Same issue at the same status = duplicate within the dedup window.
|
|
72
|
+
*/
|
|
73
|
+
export declare function eventDedupKey(event: GovernorEvent): string;
|
|
74
|
+
/**
|
|
75
|
+
* Create a GovernorEvent timestamp (ISO-8601 now).
|
|
76
|
+
*/
|
|
77
|
+
export declare function eventTimestamp(): string;
|
|
78
|
+
//# sourceMappingURL=event-types.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governor Event Types
|
|
3
|
+
*
|
|
4
|
+
* Discriminated union of events that flow through the GovernorEventBus.
|
|
5
|
+
* Events are produced by webhooks (real-time) and poll sweeps (periodic),
|
|
6
|
+
* then consumed by the EventDrivenGovernor for decision-making.
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Generate a deduplication key for an event.
|
|
13
|
+
* Same issue at the same status = duplicate within the dedup window.
|
|
14
|
+
*/
|
|
15
|
+
export function eventDedupKey(event) {
|
|
16
|
+
switch (event.type) {
|
|
17
|
+
case 'issue-status-changed':
|
|
18
|
+
return `${event.issueId}:${event.newStatus}`;
|
|
19
|
+
case 'comment-added':
|
|
20
|
+
return `${event.issueId}:comment:${event.commentId}`;
|
|
21
|
+
case 'session-completed':
|
|
22
|
+
return `${event.issueId}:session:${event.sessionId}`;
|
|
23
|
+
case 'poll-snapshot':
|
|
24
|
+
return `${event.issueId}:${event.issue.status}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a GovernorEvent timestamp (ISO-8601 now).
|
|
29
|
+
*/
|
|
30
|
+
export function eventTimestamp() {
|
|
31
|
+
return new Date().toISOString();
|
|
32
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governor Types
|
|
3
|
+
*
|
|
4
|
+
* Core type definitions for the Workflow Governor scan loop.
|
|
5
|
+
* The Governor periodically scans Linear projects and dispatches
|
|
6
|
+
* agent work based on issue status and configuration.
|
|
7
|
+
*/
|
|
8
|
+
import type { TopOfFunnelConfig } from './top-of-funnel.js';
|
|
9
|
+
/**
|
|
10
|
+
* Actions the Governor can take for a given issue.
|
|
11
|
+
*
|
|
12
|
+
* Each action maps to an agent work type or special handling:
|
|
13
|
+
* - trigger-research: Dispatch a research agent (Icebox, sparse description)
|
|
14
|
+
* - trigger-backlog-creation: Dispatch a backlog-creation agent (Icebox, well-researched)
|
|
15
|
+
* - trigger-development: Dispatch a development agent (Backlog)
|
|
16
|
+
* - trigger-qa: Dispatch a QA agent (Finished)
|
|
17
|
+
* - trigger-acceptance: Dispatch an acceptance agent (Delivered)
|
|
18
|
+
* - trigger-refinement: Dispatch a refinement agent (Rejected)
|
|
19
|
+
* - decompose: Trigger task decomposition (escalation strategy)
|
|
20
|
+
* - escalate-human: Create a human escalation touchpoint
|
|
21
|
+
* - none: No action needed
|
|
22
|
+
*/
|
|
23
|
+
export type GovernorAction = 'trigger-research' | 'trigger-backlog-creation' | 'trigger-development' | 'trigger-qa' | 'trigger-acceptance' | 'trigger-refinement' | 'decompose' | 'escalate-human' | 'none';
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for the Workflow Governor scan loop.
|
|
26
|
+
*/
|
|
27
|
+
export interface GovernorConfig {
|
|
28
|
+
/** Projects to scan */
|
|
29
|
+
projects: string[];
|
|
30
|
+
/** Scan interval in milliseconds (default: 60000) */
|
|
31
|
+
scanIntervalMs: number;
|
|
32
|
+
/** Maximum concurrent dispatches per scan (default: 3) */
|
|
33
|
+
maxConcurrentDispatches: number;
|
|
34
|
+
/** Enable auto-research from Icebox (default: true) */
|
|
35
|
+
enableAutoResearch: boolean;
|
|
36
|
+
/** Enable auto-backlog-creation from Icebox (default: true) */
|
|
37
|
+
enableAutoBacklogCreation: boolean;
|
|
38
|
+
/** Enable auto-development from Backlog (default: true) */
|
|
39
|
+
enableAutoDevelopment: boolean;
|
|
40
|
+
/** Enable auto-QA from Finished (default: true) */
|
|
41
|
+
enableAutoQA: boolean;
|
|
42
|
+
/** Enable auto-acceptance from Delivered (default: true) */
|
|
43
|
+
enableAutoAcceptance: boolean;
|
|
44
|
+
/** Human response timeout in milliseconds (default: 4 hours) */
|
|
45
|
+
humanResponseTimeoutMs: number;
|
|
46
|
+
/** Top-of-funnel configuration overrides */
|
|
47
|
+
topOfFunnel?: Partial<TopOfFunnelConfig>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Sensible defaults for the Governor configuration.
|
|
51
|
+
*/
|
|
52
|
+
export declare const DEFAULT_GOVERNOR_CONFIG: GovernorConfig;
|
|
53
|
+
/**
|
|
54
|
+
* Result of a single project scan pass.
|
|
55
|
+
*/
|
|
56
|
+
export interface ScanResult {
|
|
57
|
+
project: string;
|
|
58
|
+
scannedIssues: number;
|
|
59
|
+
actionsDispatched: number;
|
|
60
|
+
skippedReasons: Map<string, string>;
|
|
61
|
+
errors: Array<{
|
|
62
|
+
issueId: string;
|
|
63
|
+
error: string;
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Minimal issue representation used by the Governor.
|
|
68
|
+
* Intentionally decoupled from the Linear SDK types so the Governor
|
|
69
|
+
* can be tested and used with any issue source.
|
|
70
|
+
*/
|
|
71
|
+
export interface GovernorIssue {
|
|
72
|
+
id: string;
|
|
73
|
+
identifier: string;
|
|
74
|
+
title: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
status: string;
|
|
77
|
+
labels: string[];
|
|
78
|
+
createdAt: number;
|
|
79
|
+
parentId?: string;
|
|
80
|
+
project?: string;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=governor-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governor-types.d.ts","sourceRoot":"","sources":["../../../src/governor/governor-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAM3D;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,0BAA0B,GAC1B,qBAAqB,GACrB,YAAY,GACZ,oBAAoB,GACpB,oBAAoB,GACpB,WAAW,GACX,gBAAgB,GAChB,MAAM,CAAA;AAMV;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,uBAAuB;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAA;IACtB,0DAA0D;IAC1D,uBAAuB,EAAE,MAAM,CAAA;IAC/B,uDAAuD;IACvD,kBAAkB,EAAE,OAAO,CAAA;IAC3B,+DAA+D;IAC/D,yBAAyB,EAAE,OAAO,CAAA;IAClC,2DAA2D;IAC3D,qBAAqB,EAAE,OAAO,CAAA;IAC9B,mDAAmD;IACnD,YAAY,EAAE,OAAO,CAAA;IACrB,4DAA4D;IAC5D,oBAAoB,EAAE,OAAO,CAAA;IAC7B,gEAAgE;IAChE,sBAAsB,EAAE,MAAM,CAAA;IAC9B,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAA;CACzC;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,cAUrC,CAAA;AAMD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAClD;AAMD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governor Types
|
|
3
|
+
*
|
|
4
|
+
* Core type definitions for the Workflow Governor scan loop.
|
|
5
|
+
* The Governor periodically scans Linear projects and dispatches
|
|
6
|
+
* agent work based on issue status and configuration.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Sensible defaults for the Governor configuration.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_GOVERNOR_CONFIG = {
|
|
12
|
+
projects: [],
|
|
13
|
+
scanIntervalMs: 60_000,
|
|
14
|
+
maxConcurrentDispatches: 3,
|
|
15
|
+
enableAutoResearch: false,
|
|
16
|
+
enableAutoBacklogCreation: false,
|
|
17
|
+
enableAutoDevelopment: true,
|
|
18
|
+
enableAutoQA: true,
|
|
19
|
+
enableAutoAcceptance: true,
|
|
20
|
+
humanResponseTimeoutMs: 4 * 60 * 60 * 1000, // 4 hours
|
|
21
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Governor
|
|
3
|
+
*
|
|
4
|
+
* Periodically scans Linear projects and dispatches agent work based on
|
|
5
|
+
* issue status and configuration. The Governor is the central scheduler
|
|
6
|
+
* that replaces webhook-driven execution with a polling-based model.
|
|
7
|
+
*
|
|
8
|
+
* The Governor is designed with dependency injection so it can be tested
|
|
9
|
+
* without any external services (Linear, Redis, etc.).
|
|
10
|
+
*/
|
|
11
|
+
import type { GovernorAction, GovernorConfig, GovernorIssue, ScanResult } from './governor-types.js';
|
|
12
|
+
import type { OverridePriority } from './override-parser.js';
|
|
13
|
+
/**
|
|
14
|
+
* Abstract dependencies that the Governor needs to interact with
|
|
15
|
+
* external systems. Callers inject these at construction time.
|
|
16
|
+
*
|
|
17
|
+
* This design keeps the Governor testable and decoupled from
|
|
18
|
+
* concrete implementations (Linear SDK, Redis, etc.).
|
|
19
|
+
*/
|
|
20
|
+
export interface GovernorDependencies {
|
|
21
|
+
/** List non-terminal issues for a project */
|
|
22
|
+
listIssues: (project: string) => Promise<GovernorIssue[]>;
|
|
23
|
+
/** Check if an issue has an active agent session */
|
|
24
|
+
hasActiveSession: (issueId: string) => Promise<boolean>;
|
|
25
|
+
/** Check if an issue is within cooldown (e.g., just failed QA) */
|
|
26
|
+
isWithinCooldown: (issueId: string) => Promise<boolean>;
|
|
27
|
+
/** Check if an issue is a parent (has sub-issues) */
|
|
28
|
+
isParentIssue: (issueId: string) => Promise<boolean>;
|
|
29
|
+
/** Check if an issue has a HOLD override active */
|
|
30
|
+
isHeld: (issueId: string) => Promise<boolean>;
|
|
31
|
+
/** Get the PRIORITY override for an issue (high > medium > low) */
|
|
32
|
+
getOverridePriority: (issueId: string) => Promise<OverridePriority | null>;
|
|
33
|
+
/** Get the workflow escalation strategy for an issue */
|
|
34
|
+
getWorkflowStrategy: (issueId: string) => Promise<string | undefined>;
|
|
35
|
+
/** Check if the research phase has been completed for an issue */
|
|
36
|
+
isResearchCompleted: (issueId: string) => Promise<boolean>;
|
|
37
|
+
/** Check if the backlog-creation phase has been completed for an issue */
|
|
38
|
+
isBacklogCreationCompleted: (issueId: string) => Promise<boolean>;
|
|
39
|
+
/** Count completed agent sessions for an issue (for circuit breaker) */
|
|
40
|
+
getCompletedSessionCount: (issueId: string) => Promise<number>;
|
|
41
|
+
/** Dispatch work for an issue with a specific action */
|
|
42
|
+
dispatchWork: (issue: GovernorIssue, action: GovernorAction) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The Workflow Governor scans projects on a configurable interval,
|
|
46
|
+
* evaluates each issue against the decision engine, and dispatches
|
|
47
|
+
* agent work for actionable issues.
|
|
48
|
+
*/
|
|
49
|
+
export interface WorkflowGovernorCallbacks {
|
|
50
|
+
onScanComplete?: (results: ScanResult[]) => void | Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export declare class WorkflowGovernor {
|
|
53
|
+
private readonly config;
|
|
54
|
+
private readonly deps;
|
|
55
|
+
private readonly callbacks;
|
|
56
|
+
private intervalHandle;
|
|
57
|
+
private running;
|
|
58
|
+
private scanning;
|
|
59
|
+
constructor(config: Partial<GovernorConfig>, deps: GovernorDependencies, callbacks?: WorkflowGovernorCallbacks);
|
|
60
|
+
/**
|
|
61
|
+
* Start the scan loop. Runs `scanOnce()` immediately, then repeats
|
|
62
|
+
* on the configured interval.
|
|
63
|
+
*/
|
|
64
|
+
start(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Stop the scan loop gracefully. If a scan is in progress it will
|
|
67
|
+
* finish before the Governor is fully stopped.
|
|
68
|
+
*/
|
|
69
|
+
stop(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Check if the Governor is running.
|
|
72
|
+
*/
|
|
73
|
+
isRunning(): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Run a single scan pass across all configured projects.
|
|
76
|
+
*
|
|
77
|
+
* For each project:
|
|
78
|
+
* 1. List all non-terminal issues
|
|
79
|
+
* 2. Gather context for each issue (active session, cooldown, etc.)
|
|
80
|
+
* 3. Run the decision engine
|
|
81
|
+
* 4. Dispatch actions up to `maxConcurrentDispatches`
|
|
82
|
+
*
|
|
83
|
+
* Returns an array of ScanResult (one per project).
|
|
84
|
+
*/
|
|
85
|
+
scanOnce(): Promise<ScanResult[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Scan a single project and dispatch actions.
|
|
88
|
+
*
|
|
89
|
+
* Issues are evaluated in two passes:
|
|
90
|
+
* 1. Evaluate all issues to determine actions and gather priority overrides
|
|
91
|
+
* 2. Sort actionable issues by PRIORITY override (high > medium > low > none)
|
|
92
|
+
* and dispatch up to `maxConcurrentDispatches`
|
|
93
|
+
*/
|
|
94
|
+
private scanProject;
|
|
95
|
+
/**
|
|
96
|
+
* Gather context for a single issue and run it through the decision engine.
|
|
97
|
+
*/
|
|
98
|
+
private evaluateIssue;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=governor.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Governor
|
|
3
|
+
*
|
|
4
|
+
* Periodically scans Linear projects and dispatches agent work based on
|
|
5
|
+
* issue status and configuration. The Governor is the central scheduler
|
|
6
|
+
* that replaces webhook-driven execution with a polling-based model.
|
|
7
|
+
*
|
|
8
|
+
* The Governor is designed with dependency injection so it can be tested
|
|
9
|
+
* without any external services (Linear, Redis, etc.).
|
|
10
|
+
*/
|
|
11
|
+
import { DEFAULT_GOVERNOR_CONFIG } from './governor-types.js';
|
|
12
|
+
import { decideAction } from './decision-engine.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Logging
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const log = {
|
|
17
|
+
info: (msg, data) => console.log(`[governor] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
18
|
+
warn: (msg, data) => console.warn(`[governor] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
19
|
+
error: (msg, data) => console.error(`[governor] ${msg}`, data ? JSON.stringify(data) : ''),
|
|
20
|
+
debug: (_msg, _data) => { },
|
|
21
|
+
};
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Priority ordering
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/** Map priority to a sort weight (lower = higher priority = dispatched first) */
|
|
26
|
+
function priorityWeight(priority) {
|
|
27
|
+
switch (priority) {
|
|
28
|
+
case 'high':
|
|
29
|
+
return 0;
|
|
30
|
+
case 'medium':
|
|
31
|
+
return 1;
|
|
32
|
+
case 'low':
|
|
33
|
+
return 2;
|
|
34
|
+
default:
|
|
35
|
+
return 3;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export class WorkflowGovernor {
|
|
39
|
+
config;
|
|
40
|
+
deps;
|
|
41
|
+
callbacks;
|
|
42
|
+
intervalHandle = null;
|
|
43
|
+
running = false;
|
|
44
|
+
scanning = false;
|
|
45
|
+
constructor(config, deps, callbacks) {
|
|
46
|
+
this.config = { ...DEFAULT_GOVERNOR_CONFIG, ...config };
|
|
47
|
+
this.deps = deps;
|
|
48
|
+
this.callbacks = callbacks ?? {};
|
|
49
|
+
}
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
// Lifecycle
|
|
52
|
+
// -------------------------------------------------------------------------
|
|
53
|
+
/**
|
|
54
|
+
* Start the scan loop. Runs `scanOnce()` immediately, then repeats
|
|
55
|
+
* on the configured interval.
|
|
56
|
+
*/
|
|
57
|
+
start() {
|
|
58
|
+
if (this.running) {
|
|
59
|
+
log.warn('Governor is already running');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
this.running = true;
|
|
63
|
+
log.info('Governor started', {
|
|
64
|
+
projects: this.config.projects,
|
|
65
|
+
scanIntervalMs: this.config.scanIntervalMs,
|
|
66
|
+
maxConcurrentDispatches: this.config.maxConcurrentDispatches,
|
|
67
|
+
});
|
|
68
|
+
// Run the first scan immediately (fire and forget — errors logged internally)
|
|
69
|
+
void this.scanOnce();
|
|
70
|
+
// Schedule subsequent scans
|
|
71
|
+
this.intervalHandle = setInterval(() => {
|
|
72
|
+
void this.scanOnce();
|
|
73
|
+
}, this.config.scanIntervalMs);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Stop the scan loop gracefully. If a scan is in progress it will
|
|
77
|
+
* finish before the Governor is fully stopped.
|
|
78
|
+
*/
|
|
79
|
+
stop() {
|
|
80
|
+
if (!this.running) {
|
|
81
|
+
log.warn('Governor is not running');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.running = false;
|
|
85
|
+
if (this.intervalHandle !== null) {
|
|
86
|
+
clearInterval(this.intervalHandle);
|
|
87
|
+
this.intervalHandle = null;
|
|
88
|
+
}
|
|
89
|
+
log.info('Governor stopped');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if the Governor is running.
|
|
93
|
+
*/
|
|
94
|
+
isRunning() {
|
|
95
|
+
return this.running;
|
|
96
|
+
}
|
|
97
|
+
// -------------------------------------------------------------------------
|
|
98
|
+
// Scan
|
|
99
|
+
// -------------------------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* Run a single scan pass across all configured projects.
|
|
102
|
+
*
|
|
103
|
+
* For each project:
|
|
104
|
+
* 1. List all non-terminal issues
|
|
105
|
+
* 2. Gather context for each issue (active session, cooldown, etc.)
|
|
106
|
+
* 3. Run the decision engine
|
|
107
|
+
* 4. Dispatch actions up to `maxConcurrentDispatches`
|
|
108
|
+
*
|
|
109
|
+
* Returns an array of ScanResult (one per project).
|
|
110
|
+
*/
|
|
111
|
+
async scanOnce() {
|
|
112
|
+
// Guard against overlapping scans
|
|
113
|
+
if (this.scanning) {
|
|
114
|
+
log.debug('Scan already in progress, skipping');
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
this.scanning = true;
|
|
118
|
+
const results = [];
|
|
119
|
+
try {
|
|
120
|
+
for (const project of this.config.projects) {
|
|
121
|
+
const result = await this.scanProject(project);
|
|
122
|
+
results.push(result);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
this.scanning = false;
|
|
127
|
+
}
|
|
128
|
+
await this.callbacks.onScanComplete?.(results);
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
// -------------------------------------------------------------------------
|
|
132
|
+
// Internal
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
/**
|
|
135
|
+
* Scan a single project and dispatch actions.
|
|
136
|
+
*
|
|
137
|
+
* Issues are evaluated in two passes:
|
|
138
|
+
* 1. Evaluate all issues to determine actions and gather priority overrides
|
|
139
|
+
* 2. Sort actionable issues by PRIORITY override (high > medium > low > none)
|
|
140
|
+
* and dispatch up to `maxConcurrentDispatches`
|
|
141
|
+
*/
|
|
142
|
+
async scanProject(project) {
|
|
143
|
+
const result = {
|
|
144
|
+
project,
|
|
145
|
+
scannedIssues: 0,
|
|
146
|
+
actionsDispatched: 0,
|
|
147
|
+
skippedReasons: new Map(),
|
|
148
|
+
errors: [],
|
|
149
|
+
};
|
|
150
|
+
let issues;
|
|
151
|
+
try {
|
|
152
|
+
issues = await this.deps.listIssues(project);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
156
|
+
log.error('Failed to list issues for project', { project, error: errorMsg });
|
|
157
|
+
result.errors.push({ issueId: `project:${project}`, error: errorMsg });
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
result.scannedIssues = issues.length;
|
|
161
|
+
log.info('Scanning project', {
|
|
162
|
+
project,
|
|
163
|
+
issueCount: issues.length,
|
|
164
|
+
});
|
|
165
|
+
// Pass 1: Evaluate all issues and gather priority overrides
|
|
166
|
+
const actionable = [];
|
|
167
|
+
for (const issue of issues) {
|
|
168
|
+
try {
|
|
169
|
+
const [decision, priority] = await Promise.all([
|
|
170
|
+
this.evaluateIssue(issue),
|
|
171
|
+
this.deps.getOverridePriority(issue.id),
|
|
172
|
+
]);
|
|
173
|
+
if (decision.action === 'none') {
|
|
174
|
+
result.skippedReasons.set(issue.identifier, decision.reason);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
actionable.push({
|
|
178
|
+
issue,
|
|
179
|
+
action: decision.action,
|
|
180
|
+
reason: decision.reason,
|
|
181
|
+
priority,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
186
|
+
log.error('Error evaluating issue', {
|
|
187
|
+
issueIdentifier: issue.identifier,
|
|
188
|
+
error: errorMsg,
|
|
189
|
+
});
|
|
190
|
+
result.errors.push({ issueId: issue.identifier, error: errorMsg });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Pass 2: Sort by priority override (high > medium > low > none)
|
|
194
|
+
actionable.sort((a, b) => priorityWeight(a.priority) - priorityWeight(b.priority));
|
|
195
|
+
// Pass 3: Dispatch up to the limit
|
|
196
|
+
for (const item of actionable) {
|
|
197
|
+
if (result.actionsDispatched >= this.config.maxConcurrentDispatches) {
|
|
198
|
+
log.info('Dispatch limit reached', {
|
|
199
|
+
project,
|
|
200
|
+
limit: this.config.maxConcurrentDispatches,
|
|
201
|
+
dispatched: result.actionsDispatched,
|
|
202
|
+
});
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
await this.deps.dispatchWork(item.issue, item.action);
|
|
207
|
+
result.actionsDispatched++;
|
|
208
|
+
log.info('Dispatched action', {
|
|
209
|
+
issueIdentifier: item.issue.identifier,
|
|
210
|
+
action: item.action,
|
|
211
|
+
reason: item.reason,
|
|
212
|
+
priority: item.priority ?? 'none',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
217
|
+
log.error('Error dispatching issue', {
|
|
218
|
+
issueIdentifier: item.issue.identifier,
|
|
219
|
+
error: errorMsg,
|
|
220
|
+
});
|
|
221
|
+
result.errors.push({ issueId: item.issue.identifier, error: errorMsg });
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
log.info('Project scan complete', {
|
|
225
|
+
project,
|
|
226
|
+
scanned: result.scannedIssues,
|
|
227
|
+
dispatched: result.actionsDispatched,
|
|
228
|
+
skipped: result.skippedReasons.size,
|
|
229
|
+
errors: result.errors.length,
|
|
230
|
+
});
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Gather context for a single issue and run it through the decision engine.
|
|
235
|
+
*/
|
|
236
|
+
async evaluateIssue(issue) {
|
|
237
|
+
// Gather all context in parallel for efficiency
|
|
238
|
+
const [hasActiveSession, isWithinCooldown, isParentIssue, isHeld, workflowStrategy, researchCompleted, backlogCreationCompleted, completedSessionCount,] = await Promise.all([
|
|
239
|
+
this.deps.hasActiveSession(issue.id),
|
|
240
|
+
this.deps.isWithinCooldown(issue.id),
|
|
241
|
+
this.deps.isParentIssue(issue.id),
|
|
242
|
+
this.deps.isHeld(issue.id),
|
|
243
|
+
this.deps.getWorkflowStrategy(issue.id),
|
|
244
|
+
this.deps.isResearchCompleted(issue.id),
|
|
245
|
+
this.deps.isBacklogCreationCompleted(issue.id),
|
|
246
|
+
this.deps.getCompletedSessionCount(issue.id),
|
|
247
|
+
]);
|
|
248
|
+
const ctx = {
|
|
249
|
+
issue,
|
|
250
|
+
config: this.config,
|
|
251
|
+
hasActiveSession,
|
|
252
|
+
isHeld,
|
|
253
|
+
isWithinCooldown,
|
|
254
|
+
isParentIssue,
|
|
255
|
+
workflowStrategy,
|
|
256
|
+
researchCompleted,
|
|
257
|
+
backlogCreationCompleted,
|
|
258
|
+
completedSessionCount,
|
|
259
|
+
};
|
|
260
|
+
return decideAction(ctx);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governor.test.d.ts","sourceRoot":"","sources":["../../../src/governor/governor.test.ts"],"names":[],"mappings":""}
|