@codyswann/lisa 2.93.0 → 2.94.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/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/scripts/automation-status-expected-fleet.mjs +7 -132
- package/plugins/lisa/scripts/queue-contract-resolution.mjs +458 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/src/base/scripts/automation-status-expected-fleet.mjs +7 -132
- package/plugins/src/base/scripts/queue-contract-resolution.mjs +458 -0
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"lodash": ">=4.18.1"
|
|
83
83
|
},
|
|
84
84
|
"name": "@codyswann/lisa",
|
|
85
|
-
"version": "2.
|
|
85
|
+
"version": "2.94.0",
|
|
86
86
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
87
87
|
"main": "dist/index.js",
|
|
88
88
|
"exports": {
|
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
* truth.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import {
|
|
12
|
+
resolveBuildQueueArgument,
|
|
13
|
+
resolveGithubRepoRef,
|
|
14
|
+
resolvePrdQueueArgument,
|
|
15
|
+
resolvePrdSource,
|
|
16
|
+
} from "./queue-contract-resolution.mjs";
|
|
17
|
+
|
|
11
18
|
export const AUTOMATION_EXPECTED_CADENCES = {
|
|
12
19
|
"intake-repair": {
|
|
13
20
|
human: "every 60 minutes",
|
|
@@ -33,11 +40,6 @@ export const AUTOMATION_EXPECTED_CADENCES = {
|
|
|
33
40
|
|
|
34
41
|
export const EXPLORATORY_QA_STACK_PRIORITY = ["expo", "rails", "harper-fabric"];
|
|
35
42
|
|
|
36
|
-
const GITHUB_REMOTE_PATTERNS = [
|
|
37
|
-
/github\.com[:/](?<owner>[^/]+)\/(?<repo>[^/.]+?)(?:\.git)?$/,
|
|
38
|
-
/^git@github\.com:(?<owner>[^/]+)\/(?<repo>[^/.]+?)(?:\.git)?$/,
|
|
39
|
-
];
|
|
40
|
-
|
|
41
43
|
/**
|
|
42
44
|
* @typedef {{
|
|
43
45
|
* readonly id: string
|
|
@@ -229,83 +231,6 @@ function createUnsupportedEntry(identity, id, reason) {
|
|
|
229
231
|
};
|
|
230
232
|
}
|
|
231
233
|
|
|
232
|
-
/**
|
|
233
|
-
* @param {Record<string, any>} config
|
|
234
|
-
* @param {string | undefined} source
|
|
235
|
-
* @returns {string}
|
|
236
|
-
*/
|
|
237
|
-
function resolvePrdQueueArgument(config, source) {
|
|
238
|
-
switch (source) {
|
|
239
|
-
case "github":
|
|
240
|
-
requireGithubRepo(config);
|
|
241
|
-
return "github intake_mode=prd";
|
|
242
|
-
case "linear":
|
|
243
|
-
requireLinearWorkspace(config);
|
|
244
|
-
return "linear";
|
|
245
|
-
case "notion": {
|
|
246
|
-
const databaseId = config.notion?.prdDatabaseId;
|
|
247
|
-
if (!databaseId) {
|
|
248
|
-
throw new Error(
|
|
249
|
-
"Unable to resolve the PRD queue: notion.prdDatabaseId is required when source=notion."
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
return databaseId;
|
|
253
|
-
}
|
|
254
|
-
case "confluence": {
|
|
255
|
-
const parentPageId = config.confluence?.parentPageId;
|
|
256
|
-
const spaceKey = config.confluence?.spaceKey;
|
|
257
|
-
if (!parentPageId && !spaceKey) {
|
|
258
|
-
throw new Error(
|
|
259
|
-
"Unable to resolve the PRD queue: confluence.parentPageId or confluence.spaceKey is required when source=confluence."
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
return parentPageId ?? spaceKey;
|
|
263
|
-
}
|
|
264
|
-
case "jira": {
|
|
265
|
-
const project = config.jira?.project;
|
|
266
|
-
if (!project) {
|
|
267
|
-
throw new Error(
|
|
268
|
-
"Unable to resolve the PRD queue: jira.project is required when source=jira."
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
return project;
|
|
272
|
-
}
|
|
273
|
-
default:
|
|
274
|
-
throw new Error(
|
|
275
|
-
"Unable to resolve the PRD queue from config. Set source or use tracker=github self-host with github.org/github.repo."
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* @param {Record<string, any>} config
|
|
282
|
-
* @param {string | undefined} tracker
|
|
283
|
-
* @returns {string}
|
|
284
|
-
*/
|
|
285
|
-
function resolveBuildQueueArgument(config, tracker) {
|
|
286
|
-
switch (tracker) {
|
|
287
|
-
case "github":
|
|
288
|
-
requireGithubRepo(config);
|
|
289
|
-
return "github intake_mode=build";
|
|
290
|
-
case "linear":
|
|
291
|
-
requireLinearWorkspace(config);
|
|
292
|
-
return "linear";
|
|
293
|
-
case "jira": {
|
|
294
|
-
const project = config.jira?.project;
|
|
295
|
-
if (!project) {
|
|
296
|
-
throw new Error(
|
|
297
|
-
"Unable to resolve the build queue: jira.project is required when tracker=jira."
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
return project;
|
|
301
|
-
}
|
|
302
|
-
default:
|
|
303
|
-
throw new Error(
|
|
304
|
-
"Unable to resolve the build queue from config. tracker must be github, linear, or jira."
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
234
|
/**
|
|
310
235
|
* @param {Record<string, any>} config
|
|
311
236
|
* @param {string | undefined} source
|
|
@@ -343,56 +268,6 @@ function resolveRepairQueueArgument(config, source, tracker) {
|
|
|
343
268
|
);
|
|
344
269
|
}
|
|
345
270
|
|
|
346
|
-
/**
|
|
347
|
-
* @param {Record<string, any>} config
|
|
348
|
-
* @returns {string | undefined}
|
|
349
|
-
*/
|
|
350
|
-
function resolvePrdSource(config) {
|
|
351
|
-
if (typeof config.source === "string" && config.source.length > 0) {
|
|
352
|
-
return config.source;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (
|
|
356
|
-
config.tracker === "github" &&
|
|
357
|
-
config.github?.org &&
|
|
358
|
-
config.github?.repo
|
|
359
|
-
) {
|
|
360
|
-
return "github";
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return undefined;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* @param {Record<string, any>} config
|
|
368
|
-
* @param {string | undefined} gitRemoteUrl
|
|
369
|
-
* @returns {{ readonly owner: string, readonly repo: string } | null}
|
|
370
|
-
*/
|
|
371
|
-
function resolveGithubRepoRef(config, gitRemoteUrl) {
|
|
372
|
-
const owner = config.github?.org;
|
|
373
|
-
const repo = config.github?.repo;
|
|
374
|
-
|
|
375
|
-
if (owner && repo) {
|
|
376
|
-
return { owner, repo };
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (!gitRemoteUrl) {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
for (const pattern of GITHUB_REMOTE_PATTERNS) {
|
|
384
|
-
const match = gitRemoteUrl.match(pattern);
|
|
385
|
-
if (match?.groups?.owner && match.groups.repo) {
|
|
386
|
-
return {
|
|
387
|
-
owner: match.groups.owner,
|
|
388
|
-
repo: match.groups.repo,
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return null;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
271
|
/**
|
|
397
272
|
* @param {Record<string, any>} config
|
|
398
273
|
*/
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Shared queue-contract resolution helpers for queue-facing Lisa operator
|
|
4
|
+
* surfaces. These helpers intentionally mirror the same config-resolution
|
|
5
|
+
* defaults that `intake`, `repair-intake`, and future queue-status runtime
|
|
6
|
+
* adapters need, so repo/source/tracker detection does not drift.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const GITHUB_REMOTE_PATTERNS = [
|
|
10
|
+
/github\.com[:/](?<owner>[^/]+)\/(?<repo>[^/.]+?)(?:\.git)?$/,
|
|
11
|
+
/^git@github\.com:(?<owner>[^/]+)\/(?<repo>[^/.]+?)(?:\.git)?$/,
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const DEFAULT_GITHUB_BUILD_DONE = {
|
|
15
|
+
dev: "status:on-dev",
|
|
16
|
+
staging: "status:on-stg",
|
|
17
|
+
production: "status:done",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const DEFAULT_JIRA_BUILD_DONE = {
|
|
21
|
+
dev: "On Dev",
|
|
22
|
+
staging: "On Stg",
|
|
23
|
+
production: "Done",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const DEFAULT_GITHUB_LINEAR_PRD_ROLES = {
|
|
27
|
+
draft: "prd-draft",
|
|
28
|
+
ready: "prd-ready",
|
|
29
|
+
in_review: "prd-in-review",
|
|
30
|
+
blocked: "prd-blocked",
|
|
31
|
+
ticketed: "prd-ticketed",
|
|
32
|
+
shipped: "prd-shipped",
|
|
33
|
+
verified: "prd-verified",
|
|
34
|
+
sentinel: "prd-intake-feedback",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const DEFAULT_NOTION_PRD_ROLES = {
|
|
38
|
+
draft: "Draft",
|
|
39
|
+
ready: "Ready",
|
|
40
|
+
in_review: "In Review",
|
|
41
|
+
blocked: "Blocked",
|
|
42
|
+
ticketed: "Ticketed",
|
|
43
|
+
shipped: "Shipped",
|
|
44
|
+
verified: "Verified",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const DEFAULT_CONFLUENCE_PARENT_ROLES = {
|
|
48
|
+
draft: null,
|
|
49
|
+
ready: null,
|
|
50
|
+
in_review: null,
|
|
51
|
+
blocked: null,
|
|
52
|
+
ticketed: null,
|
|
53
|
+
shipped: null,
|
|
54
|
+
verified: null,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the current repo short name per config-resolution's repo-scoping
|
|
59
|
+
* ladder: explicit `.repo`, then `github.repo`, then the origin remote basename.
|
|
60
|
+
*
|
|
61
|
+
* @param {{
|
|
62
|
+
* readonly config?: Record<string, any>
|
|
63
|
+
* readonly gitRemoteUrl?: string
|
|
64
|
+
* }} input
|
|
65
|
+
* @returns {string | null}
|
|
66
|
+
*/
|
|
67
|
+
export function resolveCurrentRepo(input = {}) {
|
|
68
|
+
const config = input.config ?? {};
|
|
69
|
+
|
|
70
|
+
if (typeof config.repo === "string" && config.repo.trim().length > 0) {
|
|
71
|
+
return config.repo.trim();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const githubRef = resolveGithubRepoRef(config, input.gitRemoteUrl);
|
|
75
|
+
if (githubRef?.repo) {
|
|
76
|
+
return githubRef.repo;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return resolveRepoNameFromRemote(input.gitRemoteUrl);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the repo's configured build tracker.
|
|
84
|
+
*
|
|
85
|
+
* @param {Record<string, any>} config
|
|
86
|
+
* @returns {string}
|
|
87
|
+
*/
|
|
88
|
+
export function resolveBuildTracker(config = {}) {
|
|
89
|
+
if (typeof config.tracker === "string" && config.tracker.trim().length > 0) {
|
|
90
|
+
return config.tracker.trim();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw new Error(
|
|
94
|
+
"Unable to resolve the build tracker from config. tracker must be github, linear, or jira."
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Resolve the repo's configured PRD source. Self-hosted GitHub falls back to
|
|
100
|
+
* `github` when `tracker=github` and a GitHub repo identity is configured.
|
|
101
|
+
*
|
|
102
|
+
* @param {Record<string, any>} config
|
|
103
|
+
* @returns {string}
|
|
104
|
+
*/
|
|
105
|
+
export function resolvePrdSource(config = {}) {
|
|
106
|
+
if (typeof config.source === "string" && config.source.trim().length > 0) {
|
|
107
|
+
return config.source.trim();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
config.tracker === "github" &&
|
|
112
|
+
config.github?.org &&
|
|
113
|
+
config.github?.repo
|
|
114
|
+
) {
|
|
115
|
+
return "github";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw new Error(
|
|
119
|
+
"Unable to resolve the PRD source from config. Set source explicitly or use tracker=github self-host with github.org/github.repo."
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the PRD queue argument shape Lisa batch skills expect.
|
|
125
|
+
*
|
|
126
|
+
* @param {Record<string, any>} config
|
|
127
|
+
* @param {string} [source]
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
export function resolvePrdQueueArgument(
|
|
131
|
+
config = {},
|
|
132
|
+
source = resolvePrdSource(config)
|
|
133
|
+
) {
|
|
134
|
+
switch (source) {
|
|
135
|
+
case "github":
|
|
136
|
+
requireGithubRepo(config);
|
|
137
|
+
return "github intake_mode=prd";
|
|
138
|
+
case "linear":
|
|
139
|
+
requireLinearWorkspace(config);
|
|
140
|
+
return "linear";
|
|
141
|
+
case "notion": {
|
|
142
|
+
const databaseId = config.notion?.prdDatabaseId;
|
|
143
|
+
if (!databaseId) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
"Unable to resolve the PRD queue: notion.prdDatabaseId is required when source=notion."
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
return databaseId;
|
|
149
|
+
}
|
|
150
|
+
case "confluence": {
|
|
151
|
+
const parentPageId = config.confluence?.parentPageId;
|
|
152
|
+
const spaceKey = config.confluence?.spaceKey;
|
|
153
|
+
if (!parentPageId && !spaceKey) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
"Unable to resolve the PRD queue: confluence.parentPageId or confluence.spaceKey is required when source=confluence."
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return parentPageId ?? spaceKey;
|
|
159
|
+
}
|
|
160
|
+
default:
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Unable to resolve the PRD queue from config. source=${String(source)} is not a supported Lisa PRD source.`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Resolve the build queue argument shape Lisa batch skills expect.
|
|
169
|
+
*
|
|
170
|
+
* @param {Record<string, any>} config
|
|
171
|
+
* @param {string} [tracker]
|
|
172
|
+
* @returns {string}
|
|
173
|
+
*/
|
|
174
|
+
export function resolveBuildQueueArgument(
|
|
175
|
+
config = {},
|
|
176
|
+
tracker = resolveBuildTracker(config)
|
|
177
|
+
) {
|
|
178
|
+
switch (tracker) {
|
|
179
|
+
case "github":
|
|
180
|
+
requireGithubRepo(config);
|
|
181
|
+
return "github intake_mode=build";
|
|
182
|
+
case "linear":
|
|
183
|
+
requireLinearWorkspace(config);
|
|
184
|
+
return "linear";
|
|
185
|
+
case "jira": {
|
|
186
|
+
const project = config.jira?.project;
|
|
187
|
+
if (!project) {
|
|
188
|
+
throw new Error(
|
|
189
|
+
"Unable to resolve the build queue: jira.project is required when tracker=jira."
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return project;
|
|
193
|
+
}
|
|
194
|
+
default:
|
|
195
|
+
throw new Error(
|
|
196
|
+
"Unable to resolve the build queue from config. tracker must be github, linear, or jira."
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Resolve the PRD lifecycle roles for the configured source vendor.
|
|
203
|
+
*
|
|
204
|
+
* @param {Record<string, any>} config
|
|
205
|
+
* @param {string} [source]
|
|
206
|
+
* @returns {Record<string, any>}
|
|
207
|
+
*/
|
|
208
|
+
export function resolvePrdLifecycleRoles(
|
|
209
|
+
config = {},
|
|
210
|
+
source = resolvePrdSource(config)
|
|
211
|
+
) {
|
|
212
|
+
switch (source) {
|
|
213
|
+
case "github":
|
|
214
|
+
return {
|
|
215
|
+
vendor: "github",
|
|
216
|
+
kind: "labels",
|
|
217
|
+
roles: resolveObjectRoles(
|
|
218
|
+
config.github?.labels?.prd,
|
|
219
|
+
DEFAULT_GITHUB_LINEAR_PRD_ROLES
|
|
220
|
+
),
|
|
221
|
+
rollup: {
|
|
222
|
+
closeOnShipped: Boolean(
|
|
223
|
+
config.github?.labels?.prd?.rollup?.closeOnShipped ?? false
|
|
224
|
+
),
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
case "linear":
|
|
228
|
+
return {
|
|
229
|
+
vendor: "linear",
|
|
230
|
+
kind: "labels",
|
|
231
|
+
roles: resolveObjectRoles(
|
|
232
|
+
config.linear?.labels?.prd,
|
|
233
|
+
DEFAULT_GITHUB_LINEAR_PRD_ROLES
|
|
234
|
+
),
|
|
235
|
+
rollup: {
|
|
236
|
+
closeOnShipped: Boolean(
|
|
237
|
+
config.linear?.labels?.prd?.rollup?.closeOnShipped ?? false
|
|
238
|
+
),
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
case "notion":
|
|
242
|
+
return {
|
|
243
|
+
vendor: "notion",
|
|
244
|
+
kind: "status",
|
|
245
|
+
statusProperty: config.notion?.statusProperty || "Status",
|
|
246
|
+
roles: resolveObjectRoles(
|
|
247
|
+
config.notion?.values,
|
|
248
|
+
DEFAULT_NOTION_PRD_ROLES
|
|
249
|
+
),
|
|
250
|
+
rollup: {
|
|
251
|
+
closeOnShipped: Boolean(
|
|
252
|
+
config.notion?.rollup?.closeOnShipped ?? false
|
|
253
|
+
),
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
case "confluence":
|
|
257
|
+
return {
|
|
258
|
+
vendor: "confluence",
|
|
259
|
+
kind: "parent-pages",
|
|
260
|
+
roles: resolveObjectRoles(
|
|
261
|
+
config.confluence?.parents,
|
|
262
|
+
DEFAULT_CONFLUENCE_PARENT_ROLES
|
|
263
|
+
),
|
|
264
|
+
rollup: {
|
|
265
|
+
closeOnShipped: Boolean(
|
|
266
|
+
config.confluence?.rollup?.closeOnShipped ?? false
|
|
267
|
+
),
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
default:
|
|
271
|
+
throw new Error(
|
|
272
|
+
`Unable to resolve PRD lifecycle roles. source=${String(source)} is not a supported Lisa PRD source.`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Resolve the build lifecycle roles for the configured tracker vendor.
|
|
279
|
+
*
|
|
280
|
+
* @param {Record<string, any>} config
|
|
281
|
+
* @param {string} [tracker]
|
|
282
|
+
* @returns {Record<string, any>}
|
|
283
|
+
*/
|
|
284
|
+
export function resolveBuildLifecycleRoles(
|
|
285
|
+
config = {},
|
|
286
|
+
tracker = resolveBuildTracker(config)
|
|
287
|
+
) {
|
|
288
|
+
switch (tracker) {
|
|
289
|
+
case "github":
|
|
290
|
+
return {
|
|
291
|
+
vendor: "github",
|
|
292
|
+
kind: "labels",
|
|
293
|
+
roles: {
|
|
294
|
+
ready: config.github?.labels?.build?.ready || "status:ready",
|
|
295
|
+
claimed:
|
|
296
|
+
config.github?.labels?.build?.claimed || "status:in-progress",
|
|
297
|
+
blocked: config.github?.labels?.build?.blocked || "status:blocked",
|
|
298
|
+
done:
|
|
299
|
+
config.github?.labels?.build?.done ||
|
|
300
|
+
structuredClone(DEFAULT_GITHUB_BUILD_DONE),
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
case "linear":
|
|
304
|
+
return {
|
|
305
|
+
vendor: "linear",
|
|
306
|
+
kind: "labels",
|
|
307
|
+
roles: {
|
|
308
|
+
ready: config.linear?.labels?.build?.ready || "status:ready",
|
|
309
|
+
claimed:
|
|
310
|
+
config.linear?.labels?.build?.claimed || "status:in-progress",
|
|
311
|
+
review: config.linear?.labels?.build?.review || "status:code-review",
|
|
312
|
+
blocked: config.linear?.labels?.build?.blocked || "status:blocked",
|
|
313
|
+
done:
|
|
314
|
+
config.linear?.labels?.build?.done ||
|
|
315
|
+
structuredClone(DEFAULT_GITHUB_BUILD_DONE),
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
case "jira":
|
|
319
|
+
return {
|
|
320
|
+
vendor: "jira",
|
|
321
|
+
kind: "workflow",
|
|
322
|
+
roles: {
|
|
323
|
+
ready: config.jira?.workflow?.ready || "Ready",
|
|
324
|
+
claimed: config.jira?.workflow?.claimed || "In Progress",
|
|
325
|
+
review: config.jira?.workflow?.review || "Code Review",
|
|
326
|
+
blocked: config.jira?.workflow?.blocked || "Blocked",
|
|
327
|
+
done:
|
|
328
|
+
config.jira?.workflow?.done ||
|
|
329
|
+
structuredClone(DEFAULT_JIRA_BUILD_DONE),
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
default:
|
|
333
|
+
throw new Error(
|
|
334
|
+
`Unable to resolve build lifecycle roles. tracker=${String(tracker)} is not a supported Lisa build tracker.`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Resolve the repo-scoped queue contract queue-status should report against.
|
|
341
|
+
*
|
|
342
|
+
* @param {{
|
|
343
|
+
* readonly config?: Record<string, any>
|
|
344
|
+
* readonly gitRemoteUrl?: string
|
|
345
|
+
* }} input
|
|
346
|
+
* @returns {{
|
|
347
|
+
* readonly currentRepo: string | null
|
|
348
|
+
* readonly source: string
|
|
349
|
+
* readonly tracker: string
|
|
350
|
+
* readonly prdQueue: { readonly argument: string } & Record<string, any>
|
|
351
|
+
* readonly buildQueue: { readonly argument: string } & Record<string, any>
|
|
352
|
+
* }}
|
|
353
|
+
*/
|
|
354
|
+
export function resolveQueueContract(input = {}) {
|
|
355
|
+
const config = input.config ?? {};
|
|
356
|
+
const source = resolvePrdSource(config);
|
|
357
|
+
const tracker = resolveBuildTracker(config);
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
currentRepo: resolveCurrentRepo(input),
|
|
361
|
+
source,
|
|
362
|
+
tracker,
|
|
363
|
+
prdQueue: {
|
|
364
|
+
argument: resolvePrdQueueArgument(config, source),
|
|
365
|
+
...resolvePrdLifecycleRoles(config, source),
|
|
366
|
+
},
|
|
367
|
+
buildQueue: {
|
|
368
|
+
argument: resolveBuildQueueArgument(config, tracker),
|
|
369
|
+
...resolveBuildLifecycleRoles(config, tracker),
|
|
370
|
+
},
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @param {Record<string, any> | undefined} values
|
|
376
|
+
* @param {Record<string, any>} defaults
|
|
377
|
+
* @returns {Record<string, any>}
|
|
378
|
+
*/
|
|
379
|
+
function resolveObjectRoles(values, defaults) {
|
|
380
|
+
return {
|
|
381
|
+
...defaults,
|
|
382
|
+
...(values ?? {}),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @param {Record<string, any>} config
|
|
388
|
+
* @param {string | undefined} gitRemoteUrl
|
|
389
|
+
* @returns {{ readonly owner: string, readonly repo: string } | null}
|
|
390
|
+
*/
|
|
391
|
+
export function resolveGithubRepoRef(config = {}, gitRemoteUrl) {
|
|
392
|
+
const owner = config.github?.org;
|
|
393
|
+
const repo = config.github?.repo;
|
|
394
|
+
|
|
395
|
+
if (owner && repo) {
|
|
396
|
+
return { owner, repo };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!gitRemoteUrl) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
for (const pattern of GITHUB_REMOTE_PATTERNS) {
|
|
404
|
+
const match = gitRemoteUrl.match(pattern);
|
|
405
|
+
if (match?.groups?.owner && match.groups.repo) {
|
|
406
|
+
return {
|
|
407
|
+
owner: match.groups.owner,
|
|
408
|
+
repo: match.groups.repo,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* @param {string | undefined} gitRemoteUrl
|
|
418
|
+
* @returns {string | null}
|
|
419
|
+
*/
|
|
420
|
+
function resolveRepoNameFromRemote(gitRemoteUrl) {
|
|
421
|
+
if (!gitRemoteUrl || typeof gitRemoteUrl !== "string") {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const trimmed = gitRemoteUrl.trim();
|
|
426
|
+
if (!trimmed) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const basename = trimmed.split(/[/:]/).pop();
|
|
431
|
+
if (!basename) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return basename.replace(/\.git$/i, "") || null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @param {Record<string, any>} config
|
|
440
|
+
*/
|
|
441
|
+
function requireGithubRepo(config) {
|
|
442
|
+
if (!config.github?.org || !config.github?.repo) {
|
|
443
|
+
throw new Error(
|
|
444
|
+
"Unable to resolve the GitHub queue: github.org and github.repo are required."
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* @param {Record<string, any>} config
|
|
451
|
+
*/
|
|
452
|
+
function requireLinearWorkspace(config) {
|
|
453
|
+
if (!config.linear?.workspace) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
"Unable to resolve the Linear queue: linear.workspace is required."
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|