@proletariat/cli 0.3.77 → 0.3.78
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/commands/pr/create.js +3 -0
- package/dist/commands/pr/create.js.map +1 -1
- package/dist/commands/work/ready.js +3 -0
- package/dist/commands/work/ready.js.map +1 -1
- package/dist/commands/work/start.js +2 -1
- package/dist/commands/work/start.js.map +1 -1
- package/dist/lib/database/migrations/0005_provider_status_mapping.d.ts +2 -0
- package/dist/lib/database/migrations/0005_provider_status_mapping.js +35 -0
- package/dist/lib/database/migrations/0005_provider_status_mapping.js.map +1 -0
- package/dist/lib/database/migrations/index.js +2 -0
- package/dist/lib/database/migrations/index.js.map +1 -1
- package/dist/lib/pmo/storage/tickets.d.ts +0 -8
- package/dist/lib/pmo/storage/tickets.js +6 -52
- package/dist/lib/pmo/storage/tickets.js.map +1 -1
- package/dist/lib/pmo/sync-manager.js +13 -2
- package/dist/lib/pmo/sync-manager.js.map +1 -1
- package/dist/lib/providers/event-emitting-provider.d.ts +64 -0
- package/dist/lib/providers/event-emitting-provider.js +129 -0
- package/dist/lib/providers/event-emitting-provider.js.map +1 -0
- package/dist/lib/providers/index.d.ts +3 -0
- package/dist/lib/providers/index.js +3 -0
- package/dist/lib/providers/index.js.map +1 -1
- package/dist/lib/providers/resolver.d.ts +11 -0
- package/dist/lib/providers/resolver.js +85 -6
- package/dist/lib/providers/resolver.js.map +1 -1
- package/dist/lib/providers/status-mapping.d.ts +64 -0
- package/dist/lib/providers/status-mapping.js +136 -0
- package/dist/lib/providers/status-mapping.js.map +1 -0
- package/dist/lib/providers/trigger-config.d.ts +98 -0
- package/dist/lib/providers/trigger-config.js +204 -0
- package/dist/lib/providers/trigger-config.js.map +1 -0
- package/dist/lib/repos/git.d.ts +51 -0
- package/dist/lib/repos/git.js +99 -0
- package/dist/lib/repos/git.js.map +1 -1
- package/dist/lib/work-lifecycle/adapter.d.ts +45 -10
- package/dist/lib/work-lifecycle/adapter.js +52 -58
- package/dist/lib/work-lifecycle/adapter.js.map +1 -1
- package/oclif.manifest.json +3575 -3574
- package/package.json +1 -1
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* Determines which provider should handle ticket operations based on the
|
|
5
5
|
* ticket's external source metadata or workspace configuration.
|
|
6
6
|
*
|
|
7
|
+
* All resolved providers are wrapped with EventEmittingProvider, making
|
|
8
|
+
* the adapter layer the central event hub. Every provider (PMO, Linear,
|
|
9
|
+
* Jira, Shortcut, Asana) is an equal peer that emits events through
|
|
10
|
+
* the same mechanism.
|
|
11
|
+
*
|
|
7
12
|
* Two resolution modes:
|
|
8
13
|
* 1. Ticket-level: resolveTicketProvider() — for operations on a specific ticket
|
|
9
14
|
* (move, delete). Uses the ticket's metadata to find the source of truth.
|
|
@@ -16,6 +21,68 @@ import { isLinearConfigured } from '../linear/config.js';
|
|
|
16
21
|
import { LinearMapper } from '../linear/mapper.js';
|
|
17
22
|
import { PMOTicketProvider } from './pmo-provider.js';
|
|
18
23
|
import { LinearTicketProvider } from './linear-provider.js';
|
|
24
|
+
import { EventEmittingProvider } from './event-emitting-provider.js';
|
|
25
|
+
/**
|
|
26
|
+
* Create a StatusResolver backed by the database.
|
|
27
|
+
* Used by EventEmittingProvider to resolve status names/categories
|
|
28
|
+
* for event emission.
|
|
29
|
+
*/
|
|
30
|
+
function createDbStatusResolver(db, storage) {
|
|
31
|
+
return {
|
|
32
|
+
resolveStatusByName(projectId, statusName) {
|
|
33
|
+
try {
|
|
34
|
+
const row = db.prepare(`
|
|
35
|
+
SELECT ws.id, ws.name, ws.category
|
|
36
|
+
FROM pmo_workflow_statuses ws
|
|
37
|
+
JOIN pmo_projects p ON p.workflow_id = ws.workflow_id
|
|
38
|
+
WHERE p.id = ? AND LOWER(ws.name) = LOWER(?)
|
|
39
|
+
`).get(projectId, statusName);
|
|
40
|
+
if (row) {
|
|
41
|
+
return { id: row.id, name: row.name, category: row.category };
|
|
42
|
+
}
|
|
43
|
+
// Fallback: search by status ID
|
|
44
|
+
const byId = db.prepare(`
|
|
45
|
+
SELECT id, name, category FROM pmo_workflow_statuses WHERE id = ?
|
|
46
|
+
`).get(statusName);
|
|
47
|
+
if (byId) {
|
|
48
|
+
return { id: byId.id, name: byId.name, category: byId.category };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Non-fatal: status resolution is best-effort
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
},
|
|
56
|
+
getTicketStatus(ticketId) {
|
|
57
|
+
try {
|
|
58
|
+
const row = db.prepare(`
|
|
59
|
+
SELECT t.status_id, ws.name, ws.category
|
|
60
|
+
FROM pmo_tickets t
|
|
61
|
+
LEFT JOIN pmo_workflow_statuses ws ON t.status_id = ws.id
|
|
62
|
+
WHERE t.id = ?
|
|
63
|
+
`).get(ticketId);
|
|
64
|
+
if (row) {
|
|
65
|
+
return {
|
|
66
|
+
statusId: row.status_id,
|
|
67
|
+
statusName: row.name,
|
|
68
|
+
statusCategory: row.category ?? null,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Non-fatal: status resolution is best-effort
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Wrap a provider with EventEmittingProvider for event emission.
|
|
81
|
+
*/
|
|
82
|
+
function wrapWithEvents(provider, db, storage, projectId) {
|
|
83
|
+
const resolver = createDbStatusResolver(db, storage);
|
|
84
|
+
return new EventEmittingProvider(provider, resolver, projectId);
|
|
85
|
+
}
|
|
19
86
|
/**
|
|
20
87
|
* Resolve the correct provider for a given ticket.
|
|
21
88
|
*
|
|
@@ -23,6 +90,9 @@ import { LinearTicketProvider } from './linear-provider.js';
|
|
|
23
90
|
* - external_source = 'linear' + configured + inbound/bidirectional → Linear
|
|
24
91
|
* - Otherwise → PMO
|
|
25
92
|
*
|
|
93
|
+
* The resolved provider is wrapped with EventEmittingProvider so that
|
|
94
|
+
* events are emitted at the adapter layer, not the storage layer.
|
|
95
|
+
*
|
|
26
96
|
* @param ticketId - The PMO ticket ID
|
|
27
97
|
* @param projectId - The PMO project ID
|
|
28
98
|
* @param db - Database handle for config/mapping lookups
|
|
@@ -42,12 +112,14 @@ export function resolveTicketProvider(ticketId, projectId, db, storage, metadata
|
|
|
42
112
|
// - 'bidirectional' = both directions synced → write to Linear directly
|
|
43
113
|
// - 'outbound' = ticket was created in PMO and pushed to Linear → PMO is source of truth
|
|
44
114
|
if (mapping.syncDirection !== 'outbound') {
|
|
45
|
-
|
|
115
|
+
const inner = new LinearTicketProvider(db, storage, projectId, null);
|
|
116
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
46
117
|
}
|
|
47
118
|
}
|
|
48
119
|
}
|
|
49
120
|
// Default: local PMO
|
|
50
|
-
|
|
121
|
+
const inner = new PMOTicketProvider(storage, projectId);
|
|
122
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
51
123
|
}
|
|
52
124
|
/**
|
|
53
125
|
* Resolve the correct provider for project-level operations (list, create).
|
|
@@ -55,6 +127,9 @@ export function resolveTicketProvider(ticketId, projectId, db, storage, metadata
|
|
|
55
127
|
* Unlike resolveTicketProvider, this doesn't require a specific ticket.
|
|
56
128
|
* It checks workspace configuration to determine the active provider.
|
|
57
129
|
*
|
|
130
|
+
* The resolved provider is wrapped with EventEmittingProvider so that
|
|
131
|
+
* events are emitted at the adapter layer, not the storage layer.
|
|
132
|
+
*
|
|
58
133
|
* @param db - Database handle for config lookups
|
|
59
134
|
* @param storage - Storage instance
|
|
60
135
|
* @param projectId - The PMO project ID
|
|
@@ -63,20 +138,24 @@ export function resolveTicketProvider(ticketId, projectId, db, storage, metadata
|
|
|
63
138
|
*/
|
|
64
139
|
export function resolveProjectProvider(db, storage, projectId, source) {
|
|
65
140
|
if (source === 'pmo') {
|
|
66
|
-
|
|
141
|
+
const inner = new PMOTicketProvider(storage, projectId);
|
|
142
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
67
143
|
}
|
|
68
144
|
if (source === 'linear') {
|
|
69
|
-
|
|
145
|
+
const inner = new LinearTicketProvider(db, storage, projectId, null);
|
|
146
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
70
147
|
}
|
|
71
148
|
// auto: use Linear when it's configured in the workspace
|
|
72
149
|
try {
|
|
73
150
|
if (isLinearConfigured(db)) {
|
|
74
|
-
|
|
151
|
+
const inner = new LinearTicketProvider(db, storage, projectId, null);
|
|
152
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
75
153
|
}
|
|
76
154
|
}
|
|
77
155
|
catch {
|
|
78
156
|
// workspace_settings table may not exist in older/test databases
|
|
79
157
|
}
|
|
80
|
-
|
|
158
|
+
const inner = new PMOTicketProvider(storage, projectId);
|
|
159
|
+
return wrapWithEvents(inner, db, storage, projectId);
|
|
81
160
|
}
|
|
82
161
|
//# sourceMappingURL=resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/lib/providers/resolver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/lib/providers/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Status Mapping
|
|
3
|
+
*
|
|
4
|
+
* Configurable mapping between provider-specific status names and
|
|
5
|
+
* canonical workflow statuses. Each provider (Linear, Jira, Shortcut,
|
|
6
|
+
* Asana, etc.) may use different status vocabularies. This module
|
|
7
|
+
* translates between them.
|
|
8
|
+
*
|
|
9
|
+
* Example mappings:
|
|
10
|
+
* linear: "In Review" → canonical: "Review"
|
|
11
|
+
* jira: "Code Review" → canonical: "Review"
|
|
12
|
+
* asana: "QA" → canonical: "Review"
|
|
13
|
+
*
|
|
14
|
+
* When no mapping is configured, the system falls back to:
|
|
15
|
+
* 1. Exact name match
|
|
16
|
+
* 2. Category-based matching (e.g., 'started' category)
|
|
17
|
+
*/
|
|
18
|
+
import type Database from 'better-sqlite3';
|
|
19
|
+
import type { StateCategory } from '../pmo/types.js';
|
|
20
|
+
export interface StatusMapping {
|
|
21
|
+
provider: string;
|
|
22
|
+
providerStatus: string;
|
|
23
|
+
canonicalStatus: string;
|
|
24
|
+
canonicalCategory: StateCategory | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* ProviderStatusMappingStore manages the pmo_provider_status_map table.
|
|
28
|
+
* Provides CRUD operations for status mappings per provider.
|
|
29
|
+
*/
|
|
30
|
+
export declare class ProviderStatusMappingStore {
|
|
31
|
+
private db;
|
|
32
|
+
constructor(db: Database.Database);
|
|
33
|
+
/**
|
|
34
|
+
* Get the canonical status for a provider-specific status.
|
|
35
|
+
* Returns null if no mapping is configured.
|
|
36
|
+
*/
|
|
37
|
+
getCanonicalStatus(provider: string, providerStatus: string): StatusMapping | null;
|
|
38
|
+
/**
|
|
39
|
+
* Get the provider-specific status for a canonical status.
|
|
40
|
+
* Returns null if no mapping is configured.
|
|
41
|
+
*/
|
|
42
|
+
getProviderStatus(provider: string, canonicalStatus: string): StatusMapping | null;
|
|
43
|
+
/**
|
|
44
|
+
* List all status mappings for a provider.
|
|
45
|
+
*/
|
|
46
|
+
listMappings(provider: string): StatusMapping[];
|
|
47
|
+
/**
|
|
48
|
+
* Add or update a status mapping for a provider.
|
|
49
|
+
*/
|
|
50
|
+
upsertMapping(mapping: StatusMapping): void;
|
|
51
|
+
/**
|
|
52
|
+
* Remove a specific status mapping.
|
|
53
|
+
*/
|
|
54
|
+
removeMapping(provider: string, providerStatus: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Remove all status mappings for a provider.
|
|
57
|
+
*/
|
|
58
|
+
clearMappings(provider: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a status name from a provider to its canonical equivalent.
|
|
61
|
+
* Falls back to the original name if no mapping is found.
|
|
62
|
+
*/
|
|
63
|
+
resolveStatus(provider: string, statusName: string): string;
|
|
64
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Status Mapping
|
|
3
|
+
*
|
|
4
|
+
* Configurable mapping between provider-specific status names and
|
|
5
|
+
* canonical workflow statuses. Each provider (Linear, Jira, Shortcut,
|
|
6
|
+
* Asana, etc.) may use different status vocabularies. This module
|
|
7
|
+
* translates between them.
|
|
8
|
+
*
|
|
9
|
+
* Example mappings:
|
|
10
|
+
* linear: "In Review" → canonical: "Review"
|
|
11
|
+
* jira: "Code Review" → canonical: "Review"
|
|
12
|
+
* asana: "QA" → canonical: "Review"
|
|
13
|
+
*
|
|
14
|
+
* When no mapping is configured, the system falls back to:
|
|
15
|
+
* 1. Exact name match
|
|
16
|
+
* 2. Category-based matching (e.g., 'started' category)
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* ProviderStatusMappingStore manages the pmo_provider_status_map table.
|
|
20
|
+
* Provides CRUD operations for status mappings per provider.
|
|
21
|
+
*/
|
|
22
|
+
export class ProviderStatusMappingStore {
|
|
23
|
+
db;
|
|
24
|
+
constructor(db) {
|
|
25
|
+
this.db = db;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the canonical status for a provider-specific status.
|
|
29
|
+
* Returns null if no mapping is configured.
|
|
30
|
+
*/
|
|
31
|
+
getCanonicalStatus(provider, providerStatus) {
|
|
32
|
+
try {
|
|
33
|
+
const row = this.db.prepare(`
|
|
34
|
+
SELECT provider, provider_status, canonical_status, canonical_category
|
|
35
|
+
FROM pmo_provider_status_map
|
|
36
|
+
WHERE provider = ? AND LOWER(provider_status) = LOWER(?)
|
|
37
|
+
`).get(provider, providerStatus);
|
|
38
|
+
if (!row)
|
|
39
|
+
return null;
|
|
40
|
+
return {
|
|
41
|
+
provider: row.provider,
|
|
42
|
+
providerStatus: row.provider_status,
|
|
43
|
+
canonicalStatus: row.canonical_status,
|
|
44
|
+
canonicalCategory: row.canonical_category,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the provider-specific status for a canonical status.
|
|
53
|
+
* Returns null if no mapping is configured.
|
|
54
|
+
*/
|
|
55
|
+
getProviderStatus(provider, canonicalStatus) {
|
|
56
|
+
try {
|
|
57
|
+
const row = this.db.prepare(`
|
|
58
|
+
SELECT provider, provider_status, canonical_status, canonical_category
|
|
59
|
+
FROM pmo_provider_status_map
|
|
60
|
+
WHERE provider = ? AND LOWER(canonical_status) = LOWER(?)
|
|
61
|
+
`).get(provider, canonicalStatus);
|
|
62
|
+
if (!row)
|
|
63
|
+
return null;
|
|
64
|
+
return {
|
|
65
|
+
provider: row.provider,
|
|
66
|
+
providerStatus: row.provider_status,
|
|
67
|
+
canonicalStatus: row.canonical_status,
|
|
68
|
+
canonicalCategory: row.canonical_category,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* List all status mappings for a provider.
|
|
77
|
+
*/
|
|
78
|
+
listMappings(provider) {
|
|
79
|
+
try {
|
|
80
|
+
const rows = this.db.prepare(`
|
|
81
|
+
SELECT provider, provider_status, canonical_status, canonical_category
|
|
82
|
+
FROM pmo_provider_status_map
|
|
83
|
+
WHERE provider = ?
|
|
84
|
+
ORDER BY canonical_status
|
|
85
|
+
`).all(provider);
|
|
86
|
+
return rows.map(row => ({
|
|
87
|
+
provider: row.provider,
|
|
88
|
+
providerStatus: row.provider_status,
|
|
89
|
+
canonicalStatus: row.canonical_status,
|
|
90
|
+
canonicalCategory: row.canonical_category,
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Add or update a status mapping for a provider.
|
|
99
|
+
*/
|
|
100
|
+
upsertMapping(mapping) {
|
|
101
|
+
this.db.prepare(`
|
|
102
|
+
INSERT INTO pmo_provider_status_map (provider, provider_status, canonical_status, canonical_category)
|
|
103
|
+
VALUES (?, ?, ?, ?)
|
|
104
|
+
ON CONFLICT(provider, provider_status) DO UPDATE SET
|
|
105
|
+
canonical_status = excluded.canonical_status,
|
|
106
|
+
canonical_category = excluded.canonical_category
|
|
107
|
+
`).run(mapping.provider, mapping.providerStatus, mapping.canonicalStatus, mapping.canonicalCategory);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Remove a specific status mapping.
|
|
111
|
+
*/
|
|
112
|
+
removeMapping(provider, providerStatus) {
|
|
113
|
+
this.db.prepare(`
|
|
114
|
+
DELETE FROM pmo_provider_status_map
|
|
115
|
+
WHERE provider = ? AND provider_status = ?
|
|
116
|
+
`).run(provider, providerStatus);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Remove all status mappings for a provider.
|
|
120
|
+
*/
|
|
121
|
+
clearMappings(provider) {
|
|
122
|
+
this.db.prepare(`
|
|
123
|
+
DELETE FROM pmo_provider_status_map
|
|
124
|
+
WHERE provider = ?
|
|
125
|
+
`).run(provider);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Resolve a status name from a provider to its canonical equivalent.
|
|
129
|
+
* Falls back to the original name if no mapping is found.
|
|
130
|
+
*/
|
|
131
|
+
resolveStatus(provider, statusName) {
|
|
132
|
+
const mapping = this.getCanonicalStatus(provider, statusName);
|
|
133
|
+
return mapping?.canonicalStatus ?? statusName;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=status-mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-mapping.js","sourceRoot":"","sources":["../../../src/lib/providers/status-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAaH;;;GAGG;AACH,MAAM,OAAO,0BAA0B;IACjB;IAApB,YAAoB,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;IAAG,CAAC;IAE7C;;;OAGG;IACH,kBAAkB,CAAC,QAAgB,EAAE,cAAsB;QACzD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAI3B,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAKlB,CAAA;YAEb,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAA;YAErB,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,cAAc,EAAE,GAAG,CAAC,eAAe;gBACnC,eAAe,EAAE,GAAG,CAAC,gBAAgB;gBACrC,iBAAiB,EAAE,GAAG,CAAC,kBAA0C;aAClE,CAAA;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,QAAgB,EAAE,eAAuB;QACzD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;OAI3B,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAKnB,CAAA;YAEb,IAAI,CAAC,GAAG;gBAAE,OAAO,IAAI,CAAA;YAErB,OAAO;gBACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,cAAc,EAAE,GAAG,CAAC,eAAe;gBACnC,eAAe,EAAE,GAAG,CAAC,gBAAgB;gBACrC,iBAAiB,EAAE,GAAG,CAAC,kBAA0C;aAClE,CAAA;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAAgB;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;OAK5B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAKb,CAAA;YAEF,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACtB,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,cAAc,EAAE,GAAG,CAAC,eAAe;gBACnC,eAAe,EAAE,GAAG,CAAC,gBAAgB;gBACrC,iBAAiB,EAAE,GAAG,CAAC,kBAA0C;aAClE,CAAC,CAAC,CAAA;QACL,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,OAAsB;QAClC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;;;;KAMf,CAAC,CAAC,GAAG,CACJ,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,cAAc,EACtB,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,iBAAiB,CAC1B,CAAA;IACH,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAgB,EAAE,cAAsB;QACpD,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;KAGf,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAA;IAClC,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAgB;QAC5B,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC;;;KAGf,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,QAAgB,EAAE,UAAkB;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAC7D,OAAO,OAAO,EAAE,eAAe,IAAI,UAAU,CAAA;IAC/C,CAAC;CACF"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Trigger Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configurable triggers that map work lifecycle events to automatic
|
|
5
|
+
* column/status transitions. When a trigger event fires, the system
|
|
6
|
+
* automatically moves the affected ticket to the configured target status.
|
|
7
|
+
*
|
|
8
|
+
* Supported trigger events:
|
|
9
|
+
* - agent_started: An agent begins working on a ticket
|
|
10
|
+
* - pr_created: A pull request is created or linked
|
|
11
|
+
* - pr_merged: A pull request is merged
|
|
12
|
+
* - tests_passed: Tests pass for the work item
|
|
13
|
+
* - work_completed: Work on the item is marked complete
|
|
14
|
+
*
|
|
15
|
+
* Triggers can be scoped per provider (or '*' for all providers)
|
|
16
|
+
* and per project (or null for all projects).
|
|
17
|
+
*
|
|
18
|
+
* Example:
|
|
19
|
+
* trigger_event: 'pr_created', target_status: 'Review'
|
|
20
|
+
* → When a PR is created, move the ticket to "Review"
|
|
21
|
+
*
|
|
22
|
+
* trigger_event: 'pr_merged', target_status: 'Done'
|
|
23
|
+
* → When a PR is merged, move the ticket to "Done"
|
|
24
|
+
*/
|
|
25
|
+
import type Database from 'better-sqlite3';
|
|
26
|
+
/**
|
|
27
|
+
* Valid trigger event names that can be configured.
|
|
28
|
+
*/
|
|
29
|
+
export type TriggerEvent = 'agent_started' | 'pr_created' | 'pr_merged' | 'tests_passed' | 'work_completed';
|
|
30
|
+
export declare const TRIGGER_EVENTS: readonly TriggerEvent[];
|
|
31
|
+
export interface TriggerConfig {
|
|
32
|
+
id?: number;
|
|
33
|
+
provider: string;
|
|
34
|
+
triggerEvent: TriggerEvent;
|
|
35
|
+
targetStatus: string;
|
|
36
|
+
projectId: string | null;
|
|
37
|
+
enabled: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* ProviderTriggerStore manages the pmo_provider_triggers table.
|
|
41
|
+
* Provides CRUD operations for configurable triggers.
|
|
42
|
+
*/
|
|
43
|
+
export declare class ProviderTriggerStore {
|
|
44
|
+
private db;
|
|
45
|
+
constructor(db: Database.Database);
|
|
46
|
+
/**
|
|
47
|
+
* Get all triggers for a specific event, optionally filtered by provider and project.
|
|
48
|
+
*/
|
|
49
|
+
getTriggersForEvent(triggerEvent: TriggerEvent, provider?: string, projectId?: string | null): TriggerConfig[];
|
|
50
|
+
/**
|
|
51
|
+
* List all configured triggers.
|
|
52
|
+
*/
|
|
53
|
+
listTriggers(): TriggerConfig[];
|
|
54
|
+
/**
|
|
55
|
+
* Add or update a trigger configuration.
|
|
56
|
+
*/
|
|
57
|
+
upsertTrigger(config: TriggerConfig): void;
|
|
58
|
+
/**
|
|
59
|
+
* Remove a trigger by ID.
|
|
60
|
+
*/
|
|
61
|
+
removeTrigger(id: number): void;
|
|
62
|
+
/**
|
|
63
|
+
* Enable or disable a trigger.
|
|
64
|
+
*/
|
|
65
|
+
setEnabled(id: number, enabled: boolean): void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* TriggerHandler subscribes to work-lifecycle events on the EventBus
|
|
69
|
+
* and automatically transitions tickets based on configured triggers.
|
|
70
|
+
*/
|
|
71
|
+
export declare class TriggerHandler {
|
|
72
|
+
private unsubscribers;
|
|
73
|
+
private store;
|
|
74
|
+
private moveTicket;
|
|
75
|
+
constructor(db: Database.Database, moveTicket: (ticketId: string, projectId: string, targetStatus: string) => Promise<void>);
|
|
76
|
+
/**
|
|
77
|
+
* Start listening for work-lifecycle events and applying triggers.
|
|
78
|
+
*/
|
|
79
|
+
start(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Stop listening for events.
|
|
82
|
+
*/
|
|
83
|
+
stop(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Apply a trigger: look up configured triggers for the event
|
|
86
|
+
* and move the ticket to the target status if a match is found.
|
|
87
|
+
*/
|
|
88
|
+
private applyTrigger;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Initialize the trigger handler.
|
|
92
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
93
|
+
*/
|
|
94
|
+
export declare function initTriggerHandler(db: Database.Database, moveTicket: (ticketId: string, projectId: string, targetStatus: string) => Promise<void>): TriggerHandler;
|
|
95
|
+
/**
|
|
96
|
+
* Stop the trigger handler (primarily for testing).
|
|
97
|
+
*/
|
|
98
|
+
export declare function stopTriggerHandler(): void;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Trigger Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configurable triggers that map work lifecycle events to automatic
|
|
5
|
+
* column/status transitions. When a trigger event fires, the system
|
|
6
|
+
* automatically moves the affected ticket to the configured target status.
|
|
7
|
+
*
|
|
8
|
+
* Supported trigger events:
|
|
9
|
+
* - agent_started: An agent begins working on a ticket
|
|
10
|
+
* - pr_created: A pull request is created or linked
|
|
11
|
+
* - pr_merged: A pull request is merged
|
|
12
|
+
* - tests_passed: Tests pass for the work item
|
|
13
|
+
* - work_completed: Work on the item is marked complete
|
|
14
|
+
*
|
|
15
|
+
* Triggers can be scoped per provider (or '*' for all providers)
|
|
16
|
+
* and per project (or null for all projects).
|
|
17
|
+
*
|
|
18
|
+
* Example:
|
|
19
|
+
* trigger_event: 'pr_created', target_status: 'Review'
|
|
20
|
+
* → When a PR is created, move the ticket to "Review"
|
|
21
|
+
*
|
|
22
|
+
* trigger_event: 'pr_merged', target_status: 'Done'
|
|
23
|
+
* → When a PR is merged, move the ticket to "Done"
|
|
24
|
+
*/
|
|
25
|
+
import { getEventBus } from '../events/event-bus.js';
|
|
26
|
+
export const TRIGGER_EVENTS = [
|
|
27
|
+
'agent_started',
|
|
28
|
+
'pr_created',
|
|
29
|
+
'pr_merged',
|
|
30
|
+
'tests_passed',
|
|
31
|
+
'work_completed',
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* ProviderTriggerStore manages the pmo_provider_triggers table.
|
|
35
|
+
* Provides CRUD operations for configurable triggers.
|
|
36
|
+
*/
|
|
37
|
+
export class ProviderTriggerStore {
|
|
38
|
+
db;
|
|
39
|
+
constructor(db) {
|
|
40
|
+
this.db = db;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get all triggers for a specific event, optionally filtered by provider and project.
|
|
44
|
+
*/
|
|
45
|
+
getTriggersForEvent(triggerEvent, provider, projectId) {
|
|
46
|
+
try {
|
|
47
|
+
const rows = this.db.prepare(`
|
|
48
|
+
SELECT id, provider, trigger_event, target_status, project_id, enabled
|
|
49
|
+
FROM pmo_provider_triggers
|
|
50
|
+
WHERE trigger_event = ?
|
|
51
|
+
AND enabled = 1
|
|
52
|
+
AND (provider = '*' OR provider = ?)
|
|
53
|
+
AND (project_id IS NULL OR project_id = ?)
|
|
54
|
+
ORDER BY
|
|
55
|
+
CASE WHEN provider != '*' THEN 0 ELSE 1 END,
|
|
56
|
+
CASE WHEN project_id IS NOT NULL THEN 0 ELSE 1 END
|
|
57
|
+
`).all(triggerEvent, provider ?? '*', projectId ?? null);
|
|
58
|
+
return rows.map(row => ({
|
|
59
|
+
id: row.id,
|
|
60
|
+
provider: row.provider,
|
|
61
|
+
triggerEvent: row.trigger_event,
|
|
62
|
+
targetStatus: row.target_status,
|
|
63
|
+
projectId: row.project_id,
|
|
64
|
+
enabled: row.enabled === 1,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* List all configured triggers.
|
|
73
|
+
*/
|
|
74
|
+
listTriggers() {
|
|
75
|
+
try {
|
|
76
|
+
const rows = this.db.prepare(`
|
|
77
|
+
SELECT id, provider, trigger_event, target_status, project_id, enabled
|
|
78
|
+
FROM pmo_provider_triggers
|
|
79
|
+
ORDER BY trigger_event, provider
|
|
80
|
+
`).all();
|
|
81
|
+
return rows.map(row => ({
|
|
82
|
+
id: row.id,
|
|
83
|
+
provider: row.provider,
|
|
84
|
+
triggerEvent: row.trigger_event,
|
|
85
|
+
targetStatus: row.target_status,
|
|
86
|
+
projectId: row.project_id,
|
|
87
|
+
enabled: row.enabled === 1,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Add or update a trigger configuration.
|
|
96
|
+
*/
|
|
97
|
+
upsertTrigger(config) {
|
|
98
|
+
this.db.prepare(`
|
|
99
|
+
INSERT INTO pmo_provider_triggers (provider, trigger_event, target_status, project_id, enabled)
|
|
100
|
+
VALUES (?, ?, ?, ?, ?)
|
|
101
|
+
ON CONFLICT(provider, trigger_event, project_id) DO UPDATE SET
|
|
102
|
+
target_status = excluded.target_status,
|
|
103
|
+
enabled = excluded.enabled
|
|
104
|
+
`).run(config.provider, config.triggerEvent, config.targetStatus, config.projectId, config.enabled ? 1 : 0);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Remove a trigger by ID.
|
|
108
|
+
*/
|
|
109
|
+
removeTrigger(id) {
|
|
110
|
+
this.db.prepare('DELETE FROM pmo_provider_triggers WHERE id = ?').run(id);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Enable or disable a trigger.
|
|
114
|
+
*/
|
|
115
|
+
setEnabled(id, enabled) {
|
|
116
|
+
this.db.prepare('UPDATE pmo_provider_triggers SET enabled = ? WHERE id = ?').run(enabled ? 1 : 0, id);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* TriggerHandler subscribes to work-lifecycle events on the EventBus
|
|
121
|
+
* and automatically transitions tickets based on configured triggers.
|
|
122
|
+
*/
|
|
123
|
+
export class TriggerHandler {
|
|
124
|
+
unsubscribers = [];
|
|
125
|
+
store;
|
|
126
|
+
moveTicket;
|
|
127
|
+
constructor(db, moveTicket) {
|
|
128
|
+
this.store = new ProviderTriggerStore(db);
|
|
129
|
+
this.moveTicket = moveTicket;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Start listening for work-lifecycle events and applying triggers.
|
|
133
|
+
*/
|
|
134
|
+
start() {
|
|
135
|
+
const bus = getEventBus();
|
|
136
|
+
// agent_started trigger: fires on work:started events
|
|
137
|
+
this.unsubscribers.push(bus.on('work:started', (event) => {
|
|
138
|
+
void this.applyTrigger('agent_started', event.source, event.workItemId, event.projectId ?? null);
|
|
139
|
+
}));
|
|
140
|
+
// pr_created trigger: fires on work:pr_created events
|
|
141
|
+
this.unsubscribers.push(bus.on('work:pr_created', (event) => {
|
|
142
|
+
void this.applyTrigger('pr_created', event.source, event.workItemId, event.projectId ?? null);
|
|
143
|
+
}));
|
|
144
|
+
// pr_merged trigger: fires on work:pr_merged events
|
|
145
|
+
this.unsubscribers.push(bus.on('work:pr_merged', (event) => {
|
|
146
|
+
void this.applyTrigger('pr_merged', event.source, event.workItemId, event.projectId ?? null);
|
|
147
|
+
}));
|
|
148
|
+
// work_completed trigger: fires on work:completed events
|
|
149
|
+
this.unsubscribers.push(bus.on('work:completed', (event) => {
|
|
150
|
+
void this.applyTrigger('work_completed', event.source, event.workItemId, event.projectId ?? null);
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Stop listening for events.
|
|
155
|
+
*/
|
|
156
|
+
stop() {
|
|
157
|
+
for (const unsub of this.unsubscribers) {
|
|
158
|
+
unsub();
|
|
159
|
+
}
|
|
160
|
+
this.unsubscribers = [];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Apply a trigger: look up configured triggers for the event
|
|
164
|
+
* and move the ticket to the target status if a match is found.
|
|
165
|
+
*/
|
|
166
|
+
async applyTrigger(triggerEvent, source, workItemId, projectId) {
|
|
167
|
+
const triggers = this.store.getTriggersForEvent(triggerEvent, source, projectId);
|
|
168
|
+
if (triggers.length === 0)
|
|
169
|
+
return;
|
|
170
|
+
// Use the most specific trigger (provider-specific + project-specific first)
|
|
171
|
+
const trigger = triggers[0];
|
|
172
|
+
try {
|
|
173
|
+
await this.moveTicket(workItemId, projectId ?? '', trigger.targetStatus);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Trigger application is non-fatal
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// =============================================================================
|
|
181
|
+
// Singleton
|
|
182
|
+
// =============================================================================
|
|
183
|
+
let _handler;
|
|
184
|
+
/**
|
|
185
|
+
* Initialize the trigger handler.
|
|
186
|
+
* Safe to call multiple times — subsequent calls are no-ops.
|
|
187
|
+
*/
|
|
188
|
+
export function initTriggerHandler(db, moveTicket) {
|
|
189
|
+
if (!_handler) {
|
|
190
|
+
_handler = new TriggerHandler(db, moveTicket);
|
|
191
|
+
_handler.start();
|
|
192
|
+
}
|
|
193
|
+
return _handler;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Stop the trigger handler (primarily for testing).
|
|
197
|
+
*/
|
|
198
|
+
export function stopTriggerHandler() {
|
|
199
|
+
if (_handler) {
|
|
200
|
+
_handler.stop();
|
|
201
|
+
_handler = undefined;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=trigger-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger-config.js","sourceRoot":"","sources":["../../../src/lib/providers/trigger-config.ts"],"names":[],"mappings":"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"}
|