@gh-symphony/cli 0.2.0 → 0.2.3
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/README.md +68 -0
- package/dist/{chunk-Q3UEPUE3.js → chunk-3SKN5L3I.js} +256 -18
- package/dist/{chunk-WOVNN5NW.js → chunk-4ICDSQCJ.js} +1 -0
- package/dist/{chunk-JU3WSGMZ.js → chunk-AA3T5AAJ.js} +201 -7
- package/dist/{chunk-Z3NZOPLZ.js → chunk-BOM2BYZQ.js} +43 -0
- package/dist/{chunk-C44DYDNU.js → chunk-DLZ2XHWY.js} +6 -5
- package/dist/{chunk-B6OHDUSH.js → chunk-FAU72YC2.js} +1 -1
- package/dist/{chunk-F46FTZJE.js → chunk-PLBG7TZA.js} +290 -30
- package/dist/{chunk-6I753NYO.js → chunk-RZ3WO7OV.js} +1 -1
- package/dist/{chunk-CTTFIZYG.js → chunk-ZGNAAHLD.js} +140 -12
- package/dist/{config-cmd-2ADPUYWA.js → config-cmd-AOZVS6GU.js} +1 -1
- package/dist/{doctor-JPNA7OCD.js → doctor-GIJAH7MA.js} +602 -27
- package/dist/index.js +21 -14
- package/dist/{repo-OJLSMOR3.js → repo-LNO3Q3O7.js} +17 -10
- package/dist/{setup-PD27LSPP.js → setup-KZ3U53PY.js} +37 -47
- package/dist/{upgrade-HRI3KEO7.js → upgrade-K2PNQNWE.js} +2 -2
- package/dist/{version-JSBTKS6Q.js → version-E45DDQPQ.js} +1 -1
- package/dist/worker-entry.js +77 -9
- package/dist/{workflow-KB3TX5Z4.js → workflow-ZPERNZJT.js} +7 -7
- package/package.json +5 -5
|
@@ -7,15 +7,16 @@ import {
|
|
|
7
7
|
discoverUserProjects,
|
|
8
8
|
getGhTokenWithSource,
|
|
9
9
|
getProjectDetail,
|
|
10
|
+
listRepositoryLabels,
|
|
10
11
|
listUserProjects,
|
|
11
12
|
resolveGitHubAuth,
|
|
12
13
|
validateToken
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-BOM2BYZQ.js";
|
|
14
15
|
import {
|
|
15
16
|
formatClaudePreflightText,
|
|
16
17
|
resolveClaudeCommandBinary,
|
|
17
18
|
runClaudePreflight
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-3SKN5L3I.js";
|
|
19
20
|
|
|
20
21
|
// src/mapping/smart-defaults.ts
|
|
21
22
|
var ROLE_PATTERNS = [
|
|
@@ -347,9 +348,7 @@ function buildFrontMatter(input) {
|
|
|
347
348
|
lines.push(" kind: github-project");
|
|
348
349
|
lines.push(` project_id: ${input.projectId}`);
|
|
349
350
|
lines.push(` state_field: ${input.stateFieldName}`);
|
|
350
|
-
|
|
351
|
-
lines.push(` priority_field: ${input.priorityFieldName}`);
|
|
352
|
-
}
|
|
351
|
+
lines.push(...buildPriorityFrontMatter(input));
|
|
353
352
|
if (input.lifecycle.activeStates.length > 0) {
|
|
354
353
|
lines.push(" active_states:");
|
|
355
354
|
for (const state of input.lifecycle.activeStates) {
|
|
@@ -381,6 +380,67 @@ function buildFrontMatter(input) {
|
|
|
381
380
|
lines.push(...buildRuntimeFrontMatter(input.runtime));
|
|
382
381
|
return lines.join("\n") + "\n";
|
|
383
382
|
}
|
|
383
|
+
function buildPriorityFrontMatter(input) {
|
|
384
|
+
const lines = [];
|
|
385
|
+
if (!input.priority) {
|
|
386
|
+
return lines;
|
|
387
|
+
}
|
|
388
|
+
if (input.priority.source === "disabled") {
|
|
389
|
+
lines.push(
|
|
390
|
+
" # Priority dispatch is disabled until an operator chooses one explicit source."
|
|
391
|
+
);
|
|
392
|
+
} else {
|
|
393
|
+
lines.push(
|
|
394
|
+
" # Priority is explicit. Numbers below are editable policy (lower = higher priority)."
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
lines.push(
|
|
398
|
+
" # See docs/adr/2026-05-18_explicit-dispatch-priority-mappings.md"
|
|
399
|
+
);
|
|
400
|
+
lines.push(" priority:");
|
|
401
|
+
if (input.priority.source === "project-field") {
|
|
402
|
+
lines.push(" source: project-field");
|
|
403
|
+
lines.push(` field: ${formatYamlScalar(input.priority.field)}`);
|
|
404
|
+
lines.push(" values:");
|
|
405
|
+
for (const [name, value] of Object.entries(input.priority.values)) {
|
|
406
|
+
lines.push(` ${formatYamlKey(name)}: ${value}`);
|
|
407
|
+
}
|
|
408
|
+
return lines;
|
|
409
|
+
}
|
|
410
|
+
if (input.priority.source === "labels") {
|
|
411
|
+
lines.push(" source: labels");
|
|
412
|
+
lines.push(" labels:");
|
|
413
|
+
for (const [name, value] of Object.entries(input.priority.labels)) {
|
|
414
|
+
lines.push(` ${formatYamlKey(name)}: ${value}`);
|
|
415
|
+
}
|
|
416
|
+
return lines;
|
|
417
|
+
}
|
|
418
|
+
lines.push(" source: disabled");
|
|
419
|
+
if (input.includePriorityTemplates) {
|
|
420
|
+
lines.push("");
|
|
421
|
+
lines.push(" # Optional template: project-field priority source.");
|
|
422
|
+
lines.push(" # priority:");
|
|
423
|
+
lines.push(" # source: project-field");
|
|
424
|
+
lines.push(" # field: Priority");
|
|
425
|
+
lines.push(" # values:");
|
|
426
|
+
lines.push(" # Urgent: 0");
|
|
427
|
+
lines.push(" # High: 1");
|
|
428
|
+
lines.push("");
|
|
429
|
+
lines.push(" # Optional template: labels priority source.");
|
|
430
|
+
lines.push(" # priority:");
|
|
431
|
+
lines.push(" # source: labels");
|
|
432
|
+
lines.push(" # labels:");
|
|
433
|
+
lines.push(" # P0: 0");
|
|
434
|
+
lines.push(" # P1: 1");
|
|
435
|
+
}
|
|
436
|
+
return lines;
|
|
437
|
+
}
|
|
438
|
+
function formatYamlScalar(value) {
|
|
439
|
+
return JSON.stringify(value);
|
|
440
|
+
}
|
|
441
|
+
function formatYamlKey(value) {
|
|
442
|
+
return JSON.stringify(value);
|
|
443
|
+
}
|
|
384
444
|
function buildPromptBody(input) {
|
|
385
445
|
const statusMap = generateStatusMapWithDescriptions(input.mappings);
|
|
386
446
|
const validationGuidance = buildRepositoryValidationGuidance(
|
|
@@ -917,11 +977,7 @@ function generateReferenceWorkflow(input) {
|
|
|
917
977
|
lines.push(" kind: github-project");
|
|
918
978
|
lines.push(` project_id: ${input.projectId}`);
|
|
919
979
|
lines.push(" state_field: Status");
|
|
920
|
-
|
|
921
|
-
lines.push(` priority_field: ${input.priorityFieldName}`);
|
|
922
|
-
} else {
|
|
923
|
-
lines.push(" # priority_field: Priority");
|
|
924
|
-
}
|
|
980
|
+
lines.push(...buildReferencePriorityLines(input.priority));
|
|
925
981
|
lines.push("");
|
|
926
982
|
const activeColumns = input.statusColumns.filter((c) => c.role === "active");
|
|
927
983
|
const waitColumns = input.statusColumns.filter((c) => c.role === "wait");
|
|
@@ -1226,6 +1282,58 @@ function generateReferenceWorkflow(input) {
|
|
|
1226
1282
|
lines.push("");
|
|
1227
1283
|
return lines.join("\n");
|
|
1228
1284
|
}
|
|
1285
|
+
function buildReferencePriorityLines(priority) {
|
|
1286
|
+
const lines = [];
|
|
1287
|
+
if (priority?.source === "project-field" || priority?.source === "labels") {
|
|
1288
|
+
lines.push(
|
|
1289
|
+
" # Priority is explicit. Numbers below are editable policy (lower = higher priority)."
|
|
1290
|
+
);
|
|
1291
|
+
} else {
|
|
1292
|
+
lines.push(
|
|
1293
|
+
" # Priority dispatch is disabled until an operator chooses one explicit source."
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
lines.push(
|
|
1297
|
+
" # See docs/adr/2026-05-18_explicit-dispatch-priority-mappings.md"
|
|
1298
|
+
);
|
|
1299
|
+
if (priority?.source === "project-field") {
|
|
1300
|
+
lines.push(" priority:");
|
|
1301
|
+
lines.push(" source: project-field");
|
|
1302
|
+
lines.push(` field: ${JSON.stringify(priority.field)}`);
|
|
1303
|
+
lines.push(" values:");
|
|
1304
|
+
for (const [name, value] of Object.entries(priority.values)) {
|
|
1305
|
+
lines.push(` ${JSON.stringify(name)}: ${value}`);
|
|
1306
|
+
}
|
|
1307
|
+
return lines;
|
|
1308
|
+
}
|
|
1309
|
+
if (priority?.source === "labels") {
|
|
1310
|
+
lines.push(" priority:");
|
|
1311
|
+
lines.push(" source: labels");
|
|
1312
|
+
lines.push(" labels:");
|
|
1313
|
+
for (const [name, value] of Object.entries(priority.labels)) {
|
|
1314
|
+
lines.push(` ${JSON.stringify(name)}: ${value}`);
|
|
1315
|
+
}
|
|
1316
|
+
return lines;
|
|
1317
|
+
}
|
|
1318
|
+
lines.push(" priority:");
|
|
1319
|
+
lines.push(" source: disabled");
|
|
1320
|
+
lines.push("");
|
|
1321
|
+
lines.push(" # Optional template: project-field priority source.");
|
|
1322
|
+
lines.push(" # priority:");
|
|
1323
|
+
lines.push(" # source: project-field");
|
|
1324
|
+
lines.push(" # field: Priority");
|
|
1325
|
+
lines.push(" # values:");
|
|
1326
|
+
lines.push(" # Urgent: 0");
|
|
1327
|
+
lines.push(" # High: 1");
|
|
1328
|
+
lines.push("");
|
|
1329
|
+
lines.push(" # Optional template: labels priority source.");
|
|
1330
|
+
lines.push(" # priority:");
|
|
1331
|
+
lines.push(" # source: labels");
|
|
1332
|
+
lines.push(" # labels:");
|
|
1333
|
+
lines.push(" # P0: 0");
|
|
1334
|
+
lines.push(" # P1: 1");
|
|
1335
|
+
return lines;
|
|
1336
|
+
}
|
|
1229
1337
|
function resolveRoleAction(role) {
|
|
1230
1338
|
switch (role) {
|
|
1231
1339
|
case "active":
|
|
@@ -2037,6 +2145,35 @@ function resolvePriorityField(projectDetail, statusField) {
|
|
|
2037
2145
|
}
|
|
2038
2146
|
return { field: null, ambiguous: [] };
|
|
2039
2147
|
}
|
|
2148
|
+
function buildProjectFieldPriority(field) {
|
|
2149
|
+
return {
|
|
2150
|
+
source: "project-field",
|
|
2151
|
+
field: field.name,
|
|
2152
|
+
values: Object.fromEntries(
|
|
2153
|
+
field.options.map((option, index) => [option.name, index])
|
|
2154
|
+
)
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
function buildDisabledPriority() {
|
|
2158
|
+
return { source: "disabled" };
|
|
2159
|
+
}
|
|
2160
|
+
async function collectPriorityLabelNames(client, repositories) {
|
|
2161
|
+
const labels = /* @__PURE__ */ new Set();
|
|
2162
|
+
for (const repository of repositories) {
|
|
2163
|
+
try {
|
|
2164
|
+
const repoLabels = await listRepositoryLabels(
|
|
2165
|
+
client,
|
|
2166
|
+
repository.owner,
|
|
2167
|
+
repository.name
|
|
2168
|
+
);
|
|
2169
|
+
for (const label of repoLabels) {
|
|
2170
|
+
labels.add(label.name);
|
|
2171
|
+
}
|
|
2172
|
+
} catch {
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
return [...labels].sort((a, b) => a.localeCompare(b));
|
|
2176
|
+
}
|
|
2040
2177
|
async function promptPriorityField(priorityCandidates, options) {
|
|
2041
2178
|
if (priorityCandidates.length === 0) {
|
|
2042
2179
|
return null;
|
|
@@ -2053,7 +2190,7 @@ async function promptPriorityField(priorityCandidates, options) {
|
|
|
2053
2190
|
{
|
|
2054
2191
|
value: "__skip_priority_field__",
|
|
2055
2192
|
label: "Skip priority-aware dispatch",
|
|
2056
|
-
hint: "
|
|
2193
|
+
hint: "Write source: disabled"
|
|
2057
2194
|
}
|
|
2058
2195
|
]
|
|
2059
2196
|
})
|
|
@@ -2063,6 +2200,97 @@ async function promptPriorityField(priorityCandidates, options) {
|
|
|
2063
2200
|
}
|
|
2064
2201
|
return priorityCandidates.find((field) => field.id === selectedFieldId) ?? null;
|
|
2065
2202
|
}
|
|
2203
|
+
async function promptProjectFieldPriorityValues(field) {
|
|
2204
|
+
const values = {};
|
|
2205
|
+
for (const [index, option] of field.options.entries()) {
|
|
2206
|
+
const rawValue = await abortIfCancelled(
|
|
2207
|
+
p.text({
|
|
2208
|
+
message: `Priority value for option "${option.name}"`,
|
|
2209
|
+
placeholder: String(index),
|
|
2210
|
+
initialValue: String(index),
|
|
2211
|
+
validate: validatePriorityInteger
|
|
2212
|
+
})
|
|
2213
|
+
);
|
|
2214
|
+
values[option.name] = Number(rawValue);
|
|
2215
|
+
}
|
|
2216
|
+
return values;
|
|
2217
|
+
}
|
|
2218
|
+
async function promptPriorityConfig(input) {
|
|
2219
|
+
const hasProjectField = Boolean(input.priorityResolution.field) || input.priorityResolution.ambiguous.length > 0;
|
|
2220
|
+
const hasLabels = input.labelNames.length > 0;
|
|
2221
|
+
const selectedSource = await abortIfCancelled(
|
|
2222
|
+
p.select({
|
|
2223
|
+
message: `${input.stepLabel ?? "Priority"} \u2014 Choose one priority source:`,
|
|
2224
|
+
options: [
|
|
2225
|
+
...hasProjectField ? [
|
|
2226
|
+
{
|
|
2227
|
+
value: "project-field",
|
|
2228
|
+
label: "GitHub Project field",
|
|
2229
|
+
hint: "Map single-select options to explicit numbers"
|
|
2230
|
+
}
|
|
2231
|
+
] : [],
|
|
2232
|
+
...hasLabels ? [
|
|
2233
|
+
{
|
|
2234
|
+
value: "labels",
|
|
2235
|
+
label: "GitHub labels",
|
|
2236
|
+
hint: "Map existing repository labels to explicit numbers"
|
|
2237
|
+
}
|
|
2238
|
+
] : [],
|
|
2239
|
+
{
|
|
2240
|
+
value: "disabled",
|
|
2241
|
+
label: "Disabled",
|
|
2242
|
+
hint: "Write source: disabled"
|
|
2243
|
+
}
|
|
2244
|
+
]
|
|
2245
|
+
})
|
|
2246
|
+
);
|
|
2247
|
+
if (selectedSource === "disabled") {
|
|
2248
|
+
return { priority: buildDisabledPriority(), priorityField: null };
|
|
2249
|
+
}
|
|
2250
|
+
if (selectedSource === "labels") {
|
|
2251
|
+
const selectedLabels = await abortIfCancelled(
|
|
2252
|
+
p.multiselect({
|
|
2253
|
+
message: "Select priority labels to map:",
|
|
2254
|
+
options: input.labelNames.map((label) => ({
|
|
2255
|
+
value: label,
|
|
2256
|
+
label
|
|
2257
|
+
})),
|
|
2258
|
+
required: true
|
|
2259
|
+
})
|
|
2260
|
+
);
|
|
2261
|
+
const labels = {};
|
|
2262
|
+
for (const [index, label] of selectedLabels.entries()) {
|
|
2263
|
+
const rawValue = await abortIfCancelled(
|
|
2264
|
+
p.text({
|
|
2265
|
+
message: `Priority value for label "${label}"`,
|
|
2266
|
+
placeholder: String(index),
|
|
2267
|
+
initialValue: String(index),
|
|
2268
|
+
validate: validatePriorityInteger
|
|
2269
|
+
})
|
|
2270
|
+
);
|
|
2271
|
+
labels[label] = Number(rawValue);
|
|
2272
|
+
}
|
|
2273
|
+
return { priority: { source: "labels", labels }, priorityField: null };
|
|
2274
|
+
}
|
|
2275
|
+
const priorityField = input.priorityResolution.ambiguous.length > 0 ? await promptPriorityField(input.priorityResolution.ambiguous, {
|
|
2276
|
+
stepLabel: "Priority field"
|
|
2277
|
+
}) : input.priorityResolution.field;
|
|
2278
|
+
if (!priorityField) {
|
|
2279
|
+
return { priority: buildDisabledPriority(), priorityField: null };
|
|
2280
|
+
}
|
|
2281
|
+
return {
|
|
2282
|
+
priority: {
|
|
2283
|
+
source: "project-field",
|
|
2284
|
+
field: priorityField.name,
|
|
2285
|
+
values: await promptProjectFieldPriorityValues(priorityField)
|
|
2286
|
+
},
|
|
2287
|
+
priorityField
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
function validatePriorityInteger(value) {
|
|
2291
|
+
const trimmed = value.trim();
|
|
2292
|
+
return trimmed !== "" && Number.isInteger(Number(trimmed)) ? void 0 : "Enter an integer.";
|
|
2293
|
+
}
|
|
2066
2294
|
async function promptStateMappings(statusField, options) {
|
|
2067
2295
|
const mappings = {};
|
|
2068
2296
|
const inferred = inferAllStateRoles(statusField.options.map((o) => o.name));
|
|
@@ -2092,10 +2320,12 @@ async function promptStateMappings(statusField, options) {
|
|
|
2092
2320
|
}
|
|
2093
2321
|
async function planWorkflowArtifacts(opts) {
|
|
2094
2322
|
const environment = opts.environment ?? await detectEnvironment(opts.cwd);
|
|
2323
|
+
const priority = opts.priority ?? (opts.priorityField ? buildProjectFieldPriority(opts.priorityField) : buildDisabledPriority());
|
|
2095
2324
|
const workflowMd = generateWorkflowMarkdown({
|
|
2096
2325
|
projectId: opts.projectDetail.id,
|
|
2097
2326
|
stateFieldName: opts.statusField.name,
|
|
2098
|
-
|
|
2327
|
+
priority,
|
|
2328
|
+
includePriorityTemplates: opts.includePriorityTemplates ?? priority.source === "disabled",
|
|
2099
2329
|
mappings: opts.mappings,
|
|
2100
2330
|
lifecycle: toWorkflowLifecycleConfig(opts.statusField.name, opts.mappings),
|
|
2101
2331
|
runtime: opts.runtime,
|
|
@@ -2112,6 +2342,8 @@ async function planWorkflowArtifacts(opts) {
|
|
|
2112
2342
|
projectDetail: opts.projectDetail,
|
|
2113
2343
|
statusField: opts.statusField,
|
|
2114
2344
|
priorityField: opts.priorityField,
|
|
2345
|
+
priority,
|
|
2346
|
+
includePriorityTemplates: opts.includePriorityTemplates ?? priority.source === "disabled",
|
|
2115
2347
|
runtime: opts.runtime,
|
|
2116
2348
|
skipSkills: opts.skipSkills,
|
|
2117
2349
|
skipContext: opts.skipContext,
|
|
@@ -2146,6 +2378,7 @@ async function planEcosystem(opts) {
|
|
|
2146
2378
|
skipSkills,
|
|
2147
2379
|
skipContext
|
|
2148
2380
|
} = opts;
|
|
2381
|
+
const priority = opts.priority ?? (priorityField ? buildProjectFieldPriority(priorityField) : buildDisabledPriority());
|
|
2149
2382
|
const ghSymphonyDir = join3(cwd, ".gh-symphony");
|
|
2150
2383
|
const environment = opts.environment ?? await detectEnvironment(cwd);
|
|
2151
2384
|
const files = [];
|
|
@@ -2184,7 +2417,7 @@ async function planEcosystem(opts) {
|
|
|
2184
2417
|
role: null
|
|
2185
2418
|
})),
|
|
2186
2419
|
projectId: projectDetail.id,
|
|
2187
|
-
|
|
2420
|
+
priority,
|
|
2188
2421
|
detectedEnvironment: environment
|
|
2189
2422
|
});
|
|
2190
2423
|
files.push(
|
|
@@ -2235,7 +2468,7 @@ async function planEcosystem(opts) {
|
|
|
2235
2468
|
projectId: projectDetail.id,
|
|
2236
2469
|
githubProjectTitle: projectDetail.title,
|
|
2237
2470
|
runtime,
|
|
2238
|
-
|
|
2471
|
+
priority,
|
|
2239
2472
|
skillsDir,
|
|
2240
2473
|
skipSkills,
|
|
2241
2474
|
environment,
|
|
@@ -2284,7 +2517,7 @@ async function writeEcosystem(opts) {
|
|
|
2284
2517
|
projectId: plan.projectId,
|
|
2285
2518
|
githubProjectTitle: plan.githubProjectTitle,
|
|
2286
2519
|
runtime: plan.runtime,
|
|
2287
|
-
|
|
2520
|
+
priority: plan.priority,
|
|
2288
2521
|
skillsDir: plan.skillsDir,
|
|
2289
2522
|
skipSkills: plan.skipSkills,
|
|
2290
2523
|
afterCreateHookWritten,
|
|
@@ -2294,6 +2527,23 @@ async function writeEcosystem(opts) {
|
|
|
2294
2527
|
skillsSkipped: skillsSkipped.sort()
|
|
2295
2528
|
};
|
|
2296
2529
|
}
|
|
2530
|
+
function formatPrioritySummaryLines(priority) {
|
|
2531
|
+
if (priority.source === "disabled") {
|
|
2532
|
+
return ["Priority source disabled"];
|
|
2533
|
+
}
|
|
2534
|
+
if (priority.source === "project-field") {
|
|
2535
|
+
const mapping2 = Object.entries(priority.values).map(([name, value]) => `${name}=${value}`).join(", ");
|
|
2536
|
+
return [
|
|
2537
|
+
"Priority source project-field",
|
|
2538
|
+
`Priority mapping ${priority.field}: ${mapping2 || "none"}`
|
|
2539
|
+
];
|
|
2540
|
+
}
|
|
2541
|
+
const mapping = Object.entries(priority.labels).map(([name, value]) => `${name}=${value}`).join(", ");
|
|
2542
|
+
return [
|
|
2543
|
+
"Priority source labels",
|
|
2544
|
+
`Priority mapping ${mapping || "none"}`
|
|
2545
|
+
];
|
|
2546
|
+
}
|
|
2297
2547
|
function printEcosystemSummary(result, workflowPath, opts) {
|
|
2298
2548
|
const cwd = process.cwd();
|
|
2299
2549
|
const relWorkflow = relative(cwd, workflowPath) || "WORKFLOW.md";
|
|
@@ -2302,9 +2552,7 @@ function printEcosystemSummary(result, workflowPath, opts) {
|
|
|
2302
2552
|
`GitHub Project ${result.githubProjectTitle} (${result.projectId})`
|
|
2303
2553
|
);
|
|
2304
2554
|
lines.push(`Runtime ${result.runtime}`);
|
|
2305
|
-
|
|
2306
|
-
lines.push(`Priority field ${result.priorityFieldName}`);
|
|
2307
|
-
}
|
|
2555
|
+
lines.push(...formatPrioritySummaryLines(result.priority));
|
|
2308
2556
|
lines.push("");
|
|
2309
2557
|
lines.push("Generated files");
|
|
2310
2558
|
lines.push(` \u2713 WORKFLOW.md ${relWorkflow}`);
|
|
@@ -2358,9 +2606,7 @@ function renderDryRunPreview(workflowPath, workflowPlan, ecosystemPlan) {
|
|
|
2358
2606
|
`GitHub Project ${ecosystemPlan.githubProjectTitle} (${ecosystemPlan.projectId})`
|
|
2359
2607
|
);
|
|
2360
2608
|
lines.push(`Runtime ${ecosystemPlan.runtime}`);
|
|
2361
|
-
|
|
2362
|
-
lines.push(`Priority field ${ecosystemPlan.priorityFieldName}`);
|
|
2363
|
-
}
|
|
2609
|
+
lines.push(...formatPrioritySummaryLines(ecosystemPlan.priority));
|
|
2364
2610
|
lines.push("");
|
|
2365
2611
|
lines.push("Planned file changes");
|
|
2366
2612
|
lines.push(
|
|
@@ -2388,7 +2634,7 @@ function buildDryRunJsonResult(workflowPath, workflowPlan, ecosystemPlan) {
|
|
|
2388
2634
|
projectId: ecosystemPlan.projectId,
|
|
2389
2635
|
githubProjectTitle: ecosystemPlan.githubProjectTitle,
|
|
2390
2636
|
runtime: ecosystemPlan.runtime,
|
|
2391
|
-
|
|
2637
|
+
priority: ecosystemPlan.priority,
|
|
2392
2638
|
files: [workflowPlan, ...ecosystemPlan.files].map((file) => ({
|
|
2393
2639
|
path: file.path,
|
|
2394
2640
|
label: file.label,
|
|
@@ -2476,10 +2722,11 @@ async function runNonInteractive(flags, options) {
|
|
|
2476
2722
|
const { field: autoPriorityField, ambiguous: ambiguousPriorityFields } = resolvePriorityField(githubProject, statusField);
|
|
2477
2723
|
if (ambiguousPriorityFields.length > 0) {
|
|
2478
2724
|
process.stderr.write(
|
|
2479
|
-
`Warning: Multiple priority-like single-select fields found (${ambiguousPriorityFields.map((field) => `"${field.name}"`).join(", ")}).
|
|
2725
|
+
`Warning: Multiple priority-like single-select fields found (${ambiguousPriorityFields.map((field) => `"${field.name}"`).join(", ")}). Writing disabled priority scaffold in non-interactive mode.
|
|
2480
2726
|
`
|
|
2481
2727
|
);
|
|
2482
2728
|
}
|
|
2729
|
+
const priority = autoPriorityField ? buildProjectFieldPriority(autoPriorityField) : buildDisabledPriority();
|
|
2483
2730
|
const validation = validateStateMapping(mappings);
|
|
2484
2731
|
if (!validation.valid) {
|
|
2485
2732
|
process.stderr.write(
|
|
@@ -2497,6 +2744,8 @@ Run without --non-interactive for manual mapping.
|
|
|
2497
2744
|
projectDetail: githubProject,
|
|
2498
2745
|
statusField,
|
|
2499
2746
|
priorityField: autoPriorityField,
|
|
2747
|
+
priority,
|
|
2748
|
+
includePriorityTemplates: !autoPriorityField,
|
|
2500
2749
|
mappings,
|
|
2501
2750
|
runtime,
|
|
2502
2751
|
skipSkills: flags.skipSkills,
|
|
@@ -2520,6 +2769,8 @@ Run without --non-interactive for manual mapping.
|
|
|
2520
2769
|
projectDetail: githubProject,
|
|
2521
2770
|
statusField,
|
|
2522
2771
|
priorityField: autoPriorityField,
|
|
2772
|
+
priority,
|
|
2773
|
+
includePriorityTemplates: !autoPriorityField,
|
|
2523
2774
|
runtime,
|
|
2524
2775
|
skipSkills: flags.skipSkills,
|
|
2525
2776
|
skipContext: flags.skipContext
|
|
@@ -2626,15 +2877,18 @@ async function runInteractiveStandalone(flags, _options) {
|
|
|
2626
2877
|
return;
|
|
2627
2878
|
}
|
|
2628
2879
|
const priorityResolution = resolvePriorityField(projectDetail, statusField);
|
|
2880
|
+
const priorityLabelNames = await collectPriorityLabelNames(
|
|
2881
|
+
client,
|
|
2882
|
+
projectDetail.linkedRepositories
|
|
2883
|
+
);
|
|
2629
2884
|
const mappings = await promptStateMappings(statusField, {
|
|
2630
|
-
stepLabel:
|
|
2885
|
+
stepLabel: "Step 3/4"
|
|
2886
|
+
});
|
|
2887
|
+
const { priority, priorityField } = await promptPriorityConfig({
|
|
2888
|
+
priorityResolution,
|
|
2889
|
+
labelNames: priorityLabelNames,
|
|
2890
|
+
stepLabel: "Step 4/4"
|
|
2631
2891
|
});
|
|
2632
|
-
let priorityField = priorityResolution.field;
|
|
2633
|
-
if (priorityResolution.ambiguous.length > 0) {
|
|
2634
|
-
priorityField = await promptPriorityField(priorityResolution.ambiguous, {
|
|
2635
|
-
stepLabel: "Step 4/4"
|
|
2636
|
-
});
|
|
2637
|
-
}
|
|
2638
2892
|
const validation = validateStateMapping(mappings);
|
|
2639
2893
|
if (!validation.valid) {
|
|
2640
2894
|
p.log.error("Mapping validation failed:");
|
|
@@ -2654,6 +2908,8 @@ async function runInteractiveStandalone(flags, _options) {
|
|
|
2654
2908
|
projectDetail,
|
|
2655
2909
|
statusField,
|
|
2656
2910
|
priorityField,
|
|
2911
|
+
priority,
|
|
2912
|
+
includePriorityTemplates: priority.source === "disabled",
|
|
2657
2913
|
mappings,
|
|
2658
2914
|
runtime,
|
|
2659
2915
|
skipSkills: flags.skipSkills,
|
|
@@ -2669,6 +2925,8 @@ async function runInteractiveStandalone(flags, _options) {
|
|
|
2669
2925
|
projectDetail,
|
|
2670
2926
|
statusField,
|
|
2671
2927
|
priorityField,
|
|
2928
|
+
priority,
|
|
2929
|
+
includePriorityTemplates: priority.source === "disabled",
|
|
2672
2930
|
runtime,
|
|
2673
2931
|
skipSkills: flags.skipSkills,
|
|
2674
2932
|
skipContext: flags.skipContext
|
|
@@ -2686,6 +2944,8 @@ export {
|
|
|
2686
2944
|
resolveStatusField,
|
|
2687
2945
|
buildAutomaticStateMappings,
|
|
2688
2946
|
resolvePriorityField,
|
|
2947
|
+
collectPriorityLabelNames,
|
|
2948
|
+
promptPriorityConfig,
|
|
2689
2949
|
promptStateMappings,
|
|
2690
2950
|
planWorkflowArtifacts,
|
|
2691
2951
|
writeWorkflowPlan,
|