@codedrifters/configulator 0.0.405 → 0.0.407
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/lib/index.d.mts +286 -21
- package/lib/index.d.ts +287 -22
- package/lib/index.js +1460 -780
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1443 -780
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -280,6 +280,603 @@ function renderClaimVerificationSection() {
|
|
|
280
280
|
];
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
+
// src/agent/bundles/bundle-ownership.ts
|
|
284
|
+
var BUNDLE_OWNERSHIP = {
|
|
285
|
+
agenda: {
|
|
286
|
+
typeLabels: ["agenda"],
|
|
287
|
+
phaseLabelPrefixes: ["agenda:"],
|
|
288
|
+
scheduledTaskIds: ["worker-agenda"],
|
|
289
|
+
emitsDocs: true,
|
|
290
|
+
downstreamIssueKinds: true
|
|
291
|
+
},
|
|
292
|
+
"bcm-writer": {
|
|
293
|
+
typeLabels: ["bcm-document"],
|
|
294
|
+
phaseLabelPrefixes: ["bcm:"],
|
|
295
|
+
scheduledTaskIds: ["worker-bcm-writer"],
|
|
296
|
+
emitsDocs: true,
|
|
297
|
+
downstreamIssueKinds: true
|
|
298
|
+
},
|
|
299
|
+
"business-models": {
|
|
300
|
+
typeLabels: ["business-model"],
|
|
301
|
+
phaseLabelPrefixes: ["business-models:"],
|
|
302
|
+
scheduledTaskIds: ["worker-business-models"],
|
|
303
|
+
emitsDocs: true,
|
|
304
|
+
downstreamIssueKinds: true
|
|
305
|
+
},
|
|
306
|
+
"company-profile": {
|
|
307
|
+
typeLabels: ["company-profile"],
|
|
308
|
+
phaseLabelPrefixes: ["company:"],
|
|
309
|
+
scheduledTaskIds: ["worker-company-profile"],
|
|
310
|
+
emitsDocs: true,
|
|
311
|
+
downstreamIssueKinds: true
|
|
312
|
+
},
|
|
313
|
+
"customer-profile": {
|
|
314
|
+
typeLabels: ["customer-profile"],
|
|
315
|
+
phaseLabelPrefixes: ["customer:"],
|
|
316
|
+
scheduledTaskIds: ["worker-customer-profile"],
|
|
317
|
+
emitsDocs: true,
|
|
318
|
+
downstreamIssueKinds: true
|
|
319
|
+
},
|
|
320
|
+
"docs-sync": {
|
|
321
|
+
typeLabels: ["docs-sync"],
|
|
322
|
+
phaseLabelPrefixes: ["docs-sync:"],
|
|
323
|
+
scheduledTaskIds: ["worker-docs-sync"],
|
|
324
|
+
emitsDocs: true,
|
|
325
|
+
downstreamIssueKinds: true
|
|
326
|
+
},
|
|
327
|
+
"industry-discovery": {
|
|
328
|
+
typeLabels: ["industry-discovery"],
|
|
329
|
+
phaseLabelPrefixes: ["industry:"],
|
|
330
|
+
scheduledTaskIds: ["worker-industry-discovery"],
|
|
331
|
+
emitsDocs: true,
|
|
332
|
+
downstreamIssueKinds: true
|
|
333
|
+
},
|
|
334
|
+
"maintenance-audit": {
|
|
335
|
+
typeLabels: ["maintenance"],
|
|
336
|
+
phaseLabelPrefixes: ["maint:"],
|
|
337
|
+
scheduledTaskIds: ["worker-maintenance"],
|
|
338
|
+
emitsDocs: false,
|
|
339
|
+
downstreamIssueKinds: true
|
|
340
|
+
},
|
|
341
|
+
"meeting-analysis": {
|
|
342
|
+
typeLabels: ["meeting-processing"],
|
|
343
|
+
phaseLabelPrefixes: ["meeting:"],
|
|
344
|
+
scheduledTaskIds: ["worker-meeting-analysis"],
|
|
345
|
+
emitsDocs: true,
|
|
346
|
+
downstreamIssueKinds: true
|
|
347
|
+
},
|
|
348
|
+
orchestrator: {
|
|
349
|
+
// The orchestrator pipeline manager itself ships with the
|
|
350
|
+
// `worker-orchestrator` scheduled task. It owns no `type:*` label
|
|
351
|
+
// (it dispatches every type) and no phase-label prefix.
|
|
352
|
+
typeLabels: [],
|
|
353
|
+
phaseLabelPrefixes: [],
|
|
354
|
+
scheduledTaskIds: ["worker-orchestrator"],
|
|
355
|
+
emitsDocs: false,
|
|
356
|
+
downstreamIssueKinds: false
|
|
357
|
+
},
|
|
358
|
+
"people-profile": {
|
|
359
|
+
typeLabels: ["people-profile"],
|
|
360
|
+
phaseLabelPrefixes: ["people:"],
|
|
361
|
+
scheduledTaskIds: ["worker-people-profile"],
|
|
362
|
+
emitsDocs: true,
|
|
363
|
+
downstreamIssueKinds: true
|
|
364
|
+
},
|
|
365
|
+
"pr-review": {
|
|
366
|
+
typeLabels: ["pr-review"],
|
|
367
|
+
phaseLabelPrefixes: [],
|
|
368
|
+
scheduledTaskIds: ["worker-pr-review"],
|
|
369
|
+
emitsDocs: false,
|
|
370
|
+
downstreamIssueKinds: false
|
|
371
|
+
},
|
|
372
|
+
"regulatory-research": {
|
|
373
|
+
typeLabels: ["regulatory-research"],
|
|
374
|
+
phaseLabelPrefixes: ["regulatory:"],
|
|
375
|
+
scheduledTaskIds: ["worker-regulatory-research"],
|
|
376
|
+
emitsDocs: true,
|
|
377
|
+
downstreamIssueKinds: true
|
|
378
|
+
},
|
|
379
|
+
"requirements-analyst": {
|
|
380
|
+
typeLabels: ["requirement"],
|
|
381
|
+
phaseLabelPrefixes: ["req:"],
|
|
382
|
+
scheduledTaskIds: ["worker-requirements-analyst"],
|
|
383
|
+
emitsDocs: true,
|
|
384
|
+
downstreamIssueKinds: true
|
|
385
|
+
},
|
|
386
|
+
"requirements-reviewer": {
|
|
387
|
+
// Co-owns `type:requirement` with the analyst and writer; owns
|
|
388
|
+
// the `req:review` and `req:deprecate` phase labels exactly.
|
|
389
|
+
typeLabels: ["requirement"],
|
|
390
|
+
phaseLabelPrefixes: ["req:review", "req:deprecate"],
|
|
391
|
+
scheduledTaskIds: ["worker-requirements-reviewer"],
|
|
392
|
+
emitsDocs: true,
|
|
393
|
+
downstreamIssueKinds: true
|
|
394
|
+
},
|
|
395
|
+
"requirements-writer": {
|
|
396
|
+
// Co-owns `type:requirement` with the analyst and reviewer; owns
|
|
397
|
+
// the `req:write` phase label exactly.
|
|
398
|
+
typeLabels: ["requirement"],
|
|
399
|
+
phaseLabelPrefixes: ["req:write"],
|
|
400
|
+
scheduledTaskIds: ["worker-requirements-writer"],
|
|
401
|
+
emitsDocs: true,
|
|
402
|
+
downstreamIssueKinds: true
|
|
403
|
+
},
|
|
404
|
+
"research-pipeline": {
|
|
405
|
+
typeLabels: ["research"],
|
|
406
|
+
phaseLabelPrefixes: ["research:"],
|
|
407
|
+
scheduledTaskIds: ["worker-research"],
|
|
408
|
+
emitsDocs: true,
|
|
409
|
+
downstreamIssueKinds: true
|
|
410
|
+
},
|
|
411
|
+
"software-profile": {
|
|
412
|
+
typeLabels: ["software-profile"],
|
|
413
|
+
phaseLabelPrefixes: ["software:"],
|
|
414
|
+
scheduledTaskIds: ["worker-software-profile"],
|
|
415
|
+
emitsDocs: true,
|
|
416
|
+
downstreamIssueKinds: true
|
|
417
|
+
},
|
|
418
|
+
"standards-research": {
|
|
419
|
+
typeLabels: ["standards-research"],
|
|
420
|
+
phaseLabelPrefixes: ["standards:"],
|
|
421
|
+
scheduledTaskIds: ["worker-standards-research"],
|
|
422
|
+
emitsDocs: true,
|
|
423
|
+
downstreamIssueKinds: true
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
var CONVENTIONAL_COMMIT_TYPE_LABELS = [
|
|
427
|
+
"type:chore",
|
|
428
|
+
"type:docs",
|
|
429
|
+
"type:feat",
|
|
430
|
+
"type:fix",
|
|
431
|
+
"type:hotfix",
|
|
432
|
+
"type:refactor",
|
|
433
|
+
"type:release"
|
|
434
|
+
];
|
|
435
|
+
var PHASE_LABEL_TYPE_MAP = buildPhaseLabelTypeMap();
|
|
436
|
+
function typeLabelForPhaseLabel(phaseLabel) {
|
|
437
|
+
const exact = PHASE_LABEL_TYPE_MAP[phaseLabel];
|
|
438
|
+
if (exact !== void 0 && !phaseLabel.endsWith(":")) {
|
|
439
|
+
return exact;
|
|
440
|
+
}
|
|
441
|
+
let bestMatcher;
|
|
442
|
+
for (const matcher of Object.keys(PHASE_LABEL_TYPE_MAP)) {
|
|
443
|
+
if (!matcher.endsWith(":")) {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (!phaseLabel.startsWith(matcher)) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (bestMatcher === void 0 || matcher.length > bestMatcher.length) {
|
|
450
|
+
bestMatcher = matcher;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return bestMatcher === void 0 ? void 0 : PHASE_LABEL_TYPE_MAP[bestMatcher];
|
|
454
|
+
}
|
|
455
|
+
function resolveTypeLabelForLabels(labels) {
|
|
456
|
+
const phaseLabels = [];
|
|
457
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
458
|
+
for (const label of labels) {
|
|
459
|
+
const typeLabel = typeLabelForPhaseLabel(label);
|
|
460
|
+
if (typeLabel === void 0) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
phaseLabels.push(label);
|
|
464
|
+
candidates.add(typeLabel);
|
|
465
|
+
}
|
|
466
|
+
const candidateTypeLabels = Array.from(candidates).sort();
|
|
467
|
+
if (candidateTypeLabels.length === 0) {
|
|
468
|
+
return { outcome: "none", candidateTypeLabels: [], phaseLabels: [] };
|
|
469
|
+
}
|
|
470
|
+
if (candidateTypeLabels.length === 1) {
|
|
471
|
+
return {
|
|
472
|
+
outcome: "match",
|
|
473
|
+
typeLabel: candidateTypeLabels[0],
|
|
474
|
+
candidateTypeLabels,
|
|
475
|
+
phaseLabels
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
return { outcome: "ambiguous", candidateTypeLabels, phaseLabels };
|
|
479
|
+
}
|
|
480
|
+
function renderPhaseTypeInvariantSection(excludeBundles = []) {
|
|
481
|
+
const rows = Object.keys(PHASE_LABEL_TYPE_MAP).filter(
|
|
482
|
+
(matcher) => !isPhaseLabelMatcherOwnedByExcluded(matcher, excludeBundles)
|
|
483
|
+
).sort().map((matcher) => {
|
|
484
|
+
const display = matcher.endsWith(":") ? `${matcher}*` : matcher;
|
|
485
|
+
const kind = matcher.endsWith(":") ? "prefix" : "exact";
|
|
486
|
+
return `| \`${display}\` | ${kind} | \`${PHASE_LABEL_TYPE_MAP[matcher]}\` |`;
|
|
487
|
+
});
|
|
488
|
+
return [
|
|
489
|
+
"## Phase-label \u2192 `type:<bundle>` invariant",
|
|
490
|
+
"",
|
|
491
|
+
"Every phased-pipeline bundle pairs its `<bundle>:<phase>` labels",
|
|
492
|
+
"with exactly one `type:<bundle>` label. That type label is the",
|
|
493
|
+
"**dedup + dispatch signal**: agents de-duplicate downstream work",
|
|
494
|
+
'with `gh issue list --label "type:<bundle>"`, and Phase E derives',
|
|
495
|
+
"its funnel-tier sort key from the issue's `type:*` label. An issue",
|
|
496
|
+
"that carries the phase label but a conventional-commit `type:*`",
|
|
497
|
+
"(`type:feat`, `type:docs`, \u2026, stamped from its title prefix by the",
|
|
498
|
+
"generic create-issue workflow) is invisible to that dedup query and",
|
|
499
|
+
"mis-tiers in dispatch.",
|
|
500
|
+
"",
|
|
501
|
+
"The pairing below is derived from the canonical bundle-ownership",
|
|
502
|
+
"map \u2014 the same source of truth that generates the label registry.",
|
|
503
|
+
"Matchers ending in `*` match by prefix; the rest match exactly, and",
|
|
504
|
+
"an exact match always beats a prefix match.",
|
|
505
|
+
"",
|
|
506
|
+
"| Phase label | Match | Required type label |",
|
|
507
|
+
"|-------------|-------|---------------------|",
|
|
508
|
+
...rows,
|
|
509
|
+
"",
|
|
510
|
+
"### Enforcement",
|
|
511
|
+
"",
|
|
512
|
+
"The Phase D maintenance sweep runs the invariant in auto-correct",
|
|
513
|
+
"mode and emits one summary line:",
|
|
514
|
+
"",
|
|
515
|
+
"```",
|
|
516
|
+
"LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>",
|
|
517
|
+
"```",
|
|
518
|
+
"",
|
|
519
|
+
"A **report-only** audit is available for repos that prefer",
|
|
520
|
+
"report-then-fix over auto-correct \u2014 same sweep, no mutations:",
|
|
521
|
+
"",
|
|
522
|
+
"```bash",
|
|
523
|
+
".claude/procedures/check-blocked.sh label-invariant # report only",
|
|
524
|
+
".claude/procedures/check-blocked.sh label-invariant --fix # apply",
|
|
525
|
+
"```",
|
|
526
|
+
"",
|
|
527
|
+
"### Correction policy",
|
|
528
|
+
"",
|
|
529
|
+
"An issue must carry **exactly one** `type:*` label. Merely *adding*",
|
|
530
|
+
"the required type label to an issue that already carries a",
|
|
531
|
+
"conventional-commit one would leave two, making the funnel-tier sort",
|
|
532
|
+
"key (which reads the **first** `type:*` label) non-deterministic and",
|
|
533
|
+
"violating the label conventions. The correction therefore",
|
|
534
|
+
"**replaces**, in a single atomic `gh issue edit`, so the issue is",
|
|
535
|
+
"never observable carrying two `type:*` labels:",
|
|
536
|
+
"",
|
|
537
|
+
"| Issue state | Action |",
|
|
538
|
+
"|-------------|--------|",
|
|
539
|
+
"| Required type label present, nothing else | none \u2014 compliant, left untouched |",
|
|
540
|
+
"| No `type:*` label at all | **add** the required label |",
|
|
541
|
+
"| Only conventional-commit `type:*` label(s) | **replace** \u2014 remove them, add the required label |",
|
|
542
|
+
"| Required label present **plus** a stray conventional-commit one | **remove** the stray, leaving exactly one |",
|
|
543
|
+
"| A `type:*` label owned by a **different** bundle | **flag** `status:needs-attention` \u2014 never guessed at |",
|
|
544
|
+
"| Phase labels imply **two or more** type labels | **flag** `status:needs-attention` \u2014 never auto-corrected |",
|
|
545
|
+
"",
|
|
546
|
+
"Only a conventional-commit `type:*` label is ever removed. A",
|
|
547
|
+
"`type:*` label owned by another bundle carries real routing",
|
|
548
|
+
"information, so the sweep refuses to guess and hands the issue to a",
|
|
549
|
+
"human instead. Ambiguity is narrower than it looks: all three",
|
|
550
|
+
"requirements bundles declare `type:requirement`, so every `req:*`",
|
|
551
|
+
"phase label resolves to the same type label \u2014 genuine ambiguity",
|
|
552
|
+
"needs phase labels from two bundles with *different* type labels.",
|
|
553
|
+
"",
|
|
554
|
+
"`status:needs-attention` is applied **additively** \u2014 the base",
|
|
555
|
+
"`status:*` label always stays, per the additive-flag rule. Flagging",
|
|
556
|
+
"is idempotent: an issue already carrying the flag is reported but",
|
|
557
|
+
"not re-flagged."
|
|
558
|
+
].join("\n");
|
|
559
|
+
}
|
|
560
|
+
function isPhaseLabelMatcherOwnedByExcluded(matcher, excludeBundles) {
|
|
561
|
+
if (excludeBundles.length === 0) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
let owned = false;
|
|
565
|
+
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
566
|
+
if (!ownership.phaseLabelPrefixes.includes(matcher)) {
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
owned = true;
|
|
570
|
+
if (!excludeBundles.includes(bundleName)) {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return owned;
|
|
575
|
+
}
|
|
576
|
+
function renderPhaseTypeInvariantShellHelpers() {
|
|
577
|
+
const matchers = Object.keys(PHASE_LABEL_TYPE_MAP);
|
|
578
|
+
const exactMatchers = matchers.filter((m) => !m.endsWith(":")).sort();
|
|
579
|
+
const prefixMatchers = matchers.filter((m) => m.endsWith(":")).sort((a, b) => b.length - a.length || a.localeCompare(b));
|
|
580
|
+
const lines = [
|
|
581
|
+
"# Resolve ONE phase label to the `type:<bundle>` label its owning",
|
|
582
|
+
"# bundle declares. Echoes the label (with the `type:` prefix) or",
|
|
583
|
+
"# nothing when no bundle owns it. Exact-match branches come first,",
|
|
584
|
+
"# so `req:write` (requirements-writer) beats the `req:` prefix",
|
|
585
|
+
"# (requirements-analyst). Generated from BUNDLE_OWNERSHIP \u2014 do not",
|
|
586
|
+
"# hand-edit.",
|
|
587
|
+
"phase_label_type_of() {",
|
|
588
|
+
' case "${1:-}" in'
|
|
589
|
+
];
|
|
590
|
+
for (const matcher of exactMatchers) {
|
|
591
|
+
lines.push(` ${matcher}) echo "${PHASE_LABEL_TYPE_MAP[matcher]}" ;;`);
|
|
592
|
+
}
|
|
593
|
+
for (const matcher of prefixMatchers) {
|
|
594
|
+
lines.push(` ${matcher}*) echo "${PHASE_LABEL_TYPE_MAP[matcher]}" ;;`);
|
|
595
|
+
}
|
|
596
|
+
lines.push(
|
|
597
|
+
" *) : ;;",
|
|
598
|
+
" esac",
|
|
599
|
+
"}",
|
|
600
|
+
"",
|
|
601
|
+
"# Return 0 when the argument is a conventional-commit `type:*`",
|
|
602
|
+
"# label \u2014 the ONLY type labels the invariant correction may remove.",
|
|
603
|
+
"# A `type:*` label owned by another bundle is never removed; the",
|
|
604
|
+
"# issue is flagged for human triage instead.",
|
|
605
|
+
"is_conventional_type_label() {",
|
|
606
|
+
` case "\${1:-}" in`,
|
|
607
|
+
` ${CONVENTIONAL_COMMIT_TYPE_LABELS.join("|")}) return 0 ;;`,
|
|
608
|
+
" *) return 1 ;;",
|
|
609
|
+
" esac",
|
|
610
|
+
"}",
|
|
611
|
+
"",
|
|
612
|
+
"# Resolve an issue's FULL label list (one label per line on stdin)",
|
|
613
|
+
"# to the type label the phase-label invariant requires. Emits",
|
|
614
|
+
"# KEY=VALUE assignments the caller parses:",
|
|
615
|
+
"# OUTCOME=none \u2014 no recognised phase label; invariant N/A",
|
|
616
|
+
"# OUTCOME=match \u2014 plus TYPE_LABEL=<type:bundle>",
|
|
617
|
+
"# OUTCOME=ambiguous \u2014 plus CANDIDATE_TYPE_LABELS=<space-separated>",
|
|
618
|
+
"# PHASE_LABELS=<space-separated recognised phase labels>",
|
|
619
|
+
"phase_type_of() {",
|
|
620
|
+
" local label resolved",
|
|
621
|
+
' local matched_types=""',
|
|
622
|
+
' local matched_phase=""',
|
|
623
|
+
" while IFS= read -r label; do",
|
|
624
|
+
' [ -z "$label" ] && continue',
|
|
625
|
+
' resolved=$(phase_label_type_of "$label")',
|
|
626
|
+
' [ -z "$resolved" ] && continue',
|
|
627
|
+
' matched_phase="${matched_phase}${label} "',
|
|
628
|
+
' case " ${matched_types} " in',
|
|
629
|
+
' *" ${resolved} "*) ;;',
|
|
630
|
+
' *) matched_types="${matched_types}${resolved} " ;;',
|
|
631
|
+
" esac",
|
|
632
|
+
" done",
|
|
633
|
+
" local count=0",
|
|
634
|
+
" for resolved in $matched_types; do",
|
|
635
|
+
" count=$((count + 1))",
|
|
636
|
+
" done",
|
|
637
|
+
' if [ "$count" -eq 0 ]; then',
|
|
638
|
+
' echo "OUTCOME=none"',
|
|
639
|
+
' elif [ "$count" -eq 1 ]; then',
|
|
640
|
+
' echo "OUTCOME=match"',
|
|
641
|
+
' echo "TYPE_LABEL=${matched_types% }"',
|
|
642
|
+
" else",
|
|
643
|
+
' echo "OUTCOME=ambiguous"',
|
|
644
|
+
' echo "CANDIDATE_TYPE_LABELS=${matched_types% }"',
|
|
645
|
+
" fi",
|
|
646
|
+
' echo "PHASE_LABELS=${matched_phase% }"',
|
|
647
|
+
"}"
|
|
648
|
+
);
|
|
649
|
+
return lines.join("\n");
|
|
650
|
+
}
|
|
651
|
+
function buildPhaseLabelTypeMap() {
|
|
652
|
+
const map = {};
|
|
653
|
+
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
654
|
+
if (ownership.phaseLabelPrefixes.length === 0) {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (ownership.typeLabels.length !== 1) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
`BUNDLE_OWNERSHIP["${bundleName}"] declares ${ownership.phaseLabelPrefixes.length} phase-label matcher(s) but ${ownership.typeLabels.length} type label(s); a phase label must pair with exactly one type label`
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
const typeLabel = `type:${ownership.typeLabels[0]}`;
|
|
663
|
+
for (const matcher of ownership.phaseLabelPrefixes) {
|
|
664
|
+
const existing = map[matcher];
|
|
665
|
+
if (existing !== void 0 && existing !== typeLabel) {
|
|
666
|
+
throw new Error(
|
|
667
|
+
`Phase-label matcher "${matcher}" resolves to both "${existing}" and "${typeLabel}"; a matcher must imply exactly one type label`
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
map[matcher] = typeLabel;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return map;
|
|
674
|
+
}
|
|
675
|
+
function isTypeLabelOwnedByExcluded(typeLabel, excludedBundles) {
|
|
676
|
+
if (excludedBundles.length === 0) {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
for (const bundleName of excludedBundles) {
|
|
680
|
+
const ownership = BUNDLE_OWNERSHIP[bundleName];
|
|
681
|
+
if (!ownership) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (ownership.typeLabels.includes(typeLabel)) {
|
|
685
|
+
const owners = findOwnersOfTypeLabel(typeLabel);
|
|
686
|
+
const allExcluded = owners.every(
|
|
687
|
+
(owner) => excludedBundles.includes(owner)
|
|
688
|
+
);
|
|
689
|
+
if (allExcluded) {
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return false;
|
|
695
|
+
}
|
|
696
|
+
function isPhaseLabelOwnedByExcluded(phaseLabel, excludedBundles) {
|
|
697
|
+
if (excludedBundles.length === 0) {
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
for (const bundleName of excludedBundles) {
|
|
701
|
+
const ownership = BUNDLE_OWNERSHIP[bundleName];
|
|
702
|
+
if (!ownership) {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
for (const entry of ownership.phaseLabelPrefixes) {
|
|
706
|
+
if (entry.endsWith(":")) {
|
|
707
|
+
if (phaseLabel.startsWith(entry)) {
|
|
708
|
+
return true;
|
|
709
|
+
}
|
|
710
|
+
} else if (phaseLabel === entry) {
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
function isScheduledTaskOwnedByExcluded(taskId, excludedBundles) {
|
|
718
|
+
if (excludedBundles.length === 0) {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
for (const bundleName of excludedBundles) {
|
|
722
|
+
const ownership = BUNDLE_OWNERSHIP[bundleName];
|
|
723
|
+
if (!ownership) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (ownership.scheduledTaskIds.includes(taskId)) {
|
|
727
|
+
return true;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
function hasAnyDocsEmittingBundle(excludedBundles) {
|
|
733
|
+
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
734
|
+
if (!ownership.emitsDocs) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
if (!excludedBundles.includes(bundleName)) {
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
function hasAnyDownstreamIssueKindBundle(excludedBundles) {
|
|
744
|
+
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
745
|
+
if (!ownership.downstreamIssueKinds) {
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (!excludedBundles.includes(bundleName)) {
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
function findOwnersOfTypeLabel(typeLabel) {
|
|
755
|
+
const owners = [];
|
|
756
|
+
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
757
|
+
if (ownership.typeLabels.includes(typeLabel)) {
|
|
758
|
+
owners.push(bundleName);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
return owners;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// src/agent/bundles/issue-type.ts
|
|
765
|
+
var GITHUB_ISSUE_TYPES = ["Epic", "Feature", "Bug", "Task"];
|
|
766
|
+
var DEFAULT_GITHUB_ISSUE_TYPE = "Task";
|
|
767
|
+
var NON_DEFAULT_TITLE_PREFIX_TYPES = {
|
|
768
|
+
"epic:": "Epic",
|
|
769
|
+
"feat:": "Feature",
|
|
770
|
+
"fix:": "Bug"
|
|
771
|
+
};
|
|
772
|
+
var GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX = buildTitlePrefixTypeMap();
|
|
773
|
+
function githubIssueTypeForTitle(title) {
|
|
774
|
+
const colon = title.indexOf(":");
|
|
775
|
+
if (colon === -1) {
|
|
776
|
+
return DEFAULT_GITHUB_ISSUE_TYPE;
|
|
777
|
+
}
|
|
778
|
+
const prefix2 = title.slice(0, colon + 1).trim().toLowerCase();
|
|
779
|
+
return GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix2] ?? DEFAULT_GITHUB_ISSUE_TYPE;
|
|
780
|
+
}
|
|
781
|
+
var SET_ISSUE_TYPE_HELPER_PATH = ".claude/procedures/set-issue-type.sh";
|
|
782
|
+
function renderSetIssueTypeFallbackLines() {
|
|
783
|
+
return [
|
|
784
|
+
"```bash",
|
|
785
|
+
"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>",
|
|
786
|
+
"gh issue view <issue-number> --json id --jq '.id'",
|
|
787
|
+
"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>",
|
|
788
|
+
"```"
|
|
789
|
+
];
|
|
790
|
+
}
|
|
791
|
+
function renderGithubIssueTypeSectionLines() {
|
|
792
|
+
const defaultPrefixes = Object.keys(GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX).filter(
|
|
793
|
+
(prefix2) => GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix2] === DEFAULT_GITHUB_ISSUE_TYPE
|
|
794
|
+
).sort().map((prefix2) => `\`${prefix2}\``).join(", ");
|
|
795
|
+
return [
|
|
796
|
+
"## GitHub Issue Type",
|
|
797
|
+
"",
|
|
798
|
+
"A GitHub **issue type** is a distinct field from the `type:*` **label**:",
|
|
799
|
+
"the label routes and dedups, the issue type drives triage and Epic",
|
|
800
|
+
"tracking. Setting one does not set the other. Derive it from the",
|
|
801
|
+
"**title prefix**:",
|
|
802
|
+
"",
|
|
803
|
+
"| Prefix | GitHub Issue Type |",
|
|
804
|
+
"|--------|------------------|",
|
|
805
|
+
"| `epic:` | Epic |",
|
|
806
|
+
"| `feat:` | Feature |",
|
|
807
|
+
"| `fix:` | Bug |",
|
|
808
|
+
`| ${defaultPrefixes} | ${DEFAULT_GITHUB_ISSUE_TYPE} |`,
|
|
809
|
+
"| any bundle-phase prefix (`company:`, `req:`, \u2026), or no prefix | Task |",
|
|
810
|
+
"",
|
|
811
|
+
"### Assigning the GitHub issue type",
|
|
812
|
+
"",
|
|
813
|
+
"`gh issue create` **cannot** set the issue type \u2014 there is no `--type`",
|
|
814
|
+
"flag \u2014 so assign it in a follow-up call immediately after creation, for",
|
|
815
|
+
"every issue an agent files (auto-enqueued downstream issues included).",
|
|
816
|
+
"An issue that skips that call stays untyped forever. The",
|
|
817
|
+
"`github-workflow` bundle ships a one-step helper:",
|
|
818
|
+
"",
|
|
819
|
+
"```bash",
|
|
820
|
+
`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> <${GITHUB_ISSUE_TYPES.join("|")}>`,
|
|
821
|
+
"```",
|
|
822
|
+
"",
|
|
823
|
+
"When that helper is absent (the bundle is excluded), run the",
|
|
824
|
+
"`updateIssueIssueType` GraphQL flow it wraps:",
|
|
825
|
+
"",
|
|
826
|
+
...renderSetIssueTypeFallbackLines()
|
|
827
|
+
];
|
|
828
|
+
}
|
|
829
|
+
function renderTitlePrefixTypeBullets(indent = " ") {
|
|
830
|
+
const nonDefault = Object.entries(NON_DEFAULT_TITLE_PREFIX_TYPES).map(
|
|
831
|
+
([prefix2, issueType]) => `${indent}- \`${prefix2}\` \u2192 ${issueType}`
|
|
832
|
+
);
|
|
833
|
+
const defaults = Object.keys(GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX).filter(
|
|
834
|
+
(prefix2) => GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix2] === DEFAULT_GITHUB_ISSUE_TYPE
|
|
835
|
+
).sort().map((prefix2) => `\`${prefix2}\``).join(", ");
|
|
836
|
+
return [
|
|
837
|
+
...nonDefault,
|
|
838
|
+
`${indent}- ${defaults} \u2192 ${DEFAULT_GITHUB_ISSUE_TYPE}`,
|
|
839
|
+
`${indent}- any bundle-phase prefix (\`company:\`, \`req:\`, \`bcm:\`, \u2026) \u2192 ${DEFAULT_GITHUB_ISSUE_TYPE}`
|
|
840
|
+
];
|
|
841
|
+
}
|
|
842
|
+
function renderGithubIssueTypeSection() {
|
|
843
|
+
return renderGithubIssueTypeSectionLines().join("\n");
|
|
844
|
+
}
|
|
845
|
+
function renderIssueTypeAssignmentStep(options = {}) {
|
|
846
|
+
const indent = options.indent ?? " ";
|
|
847
|
+
const issueType = options.issueType ?? DEFAULT_GITHUB_ISSUE_TYPE;
|
|
848
|
+
const lead = options.bullet ? `${indent}- ` : indent;
|
|
849
|
+
const cont = options.bullet ? `${indent} ` : indent;
|
|
850
|
+
return [
|
|
851
|
+
`${lead}Then assign the new issue's **GitHub issue type** (\`${issueType}\`) \u2014`,
|
|
852
|
+
`${cont}the \`type:*\` label does not set it:`,
|
|
853
|
+
`${cont}\`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${issueType}\`. See`,
|
|
854
|
+
`${cont}**Assigning the GitHub issue type** for the no-helper fallback.`
|
|
855
|
+
];
|
|
856
|
+
}
|
|
857
|
+
function renderIssueTypeAssignmentBlanket(indent = "", issueType = DEFAULT_GITHUB_ISSUE_TYPE) {
|
|
858
|
+
return [
|
|
859
|
+
`${indent}**Every** issue this phase files needs a **GitHub issue type**`,
|
|
860
|
+
`${indent}assigned right after creation \u2014 the \`type:*\` label does not set`,
|
|
861
|
+
`${indent}it, and \`gh issue create\` cannot:`,
|
|
862
|
+
`${indent}\`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${issueType}\`. See`,
|
|
863
|
+
`${indent}**Assigning the GitHub issue type** for the prefix table (nearly`,
|
|
864
|
+
`${indent}every downstream issue is a \`${issueType}\`) and the no-helper fallback.`
|
|
865
|
+
];
|
|
866
|
+
}
|
|
867
|
+
function buildTitlePrefixTypeMap() {
|
|
868
|
+
const map = {};
|
|
869
|
+
for (const label of CONVENTIONAL_COMMIT_TYPE_LABELS) {
|
|
870
|
+
map[`${label.slice("type:".length)}:`] = DEFAULT_GITHUB_ISSUE_TYPE;
|
|
871
|
+
}
|
|
872
|
+
for (const [prefix2, issueType] of Object.entries(
|
|
873
|
+
NON_DEFAULT_TITLE_PREFIX_TYPES
|
|
874
|
+
)) {
|
|
875
|
+
map[prefix2] = issueType;
|
|
876
|
+
}
|
|
877
|
+
return map;
|
|
878
|
+
}
|
|
879
|
+
|
|
283
880
|
// src/agent/bundles/project-context.ts
|
|
284
881
|
var PROJECT_CONTEXT_PATH = "docs/src/content/docs/project-context.md";
|
|
285
882
|
var SUBPROJECT_ROLE_GUIDANCE = [
|
|
@@ -872,6 +1469,9 @@ var draftAgendaSkill = {
|
|
|
872
1469
|
' - `desired_outcomes` \u2014 1\u20133 bullets describing "done"',
|
|
873
1470
|
" - `pre_reads` \u2014 relative paths to existing docs (optional)",
|
|
874
1471
|
" - `related_docs` \u2014 relative paths for context (optional)",
|
|
1472
|
+
"",
|
|
1473
|
+
...renderIssueTypeAssignmentStep(),
|
|
1474
|
+
"",
|
|
875
1475
|
"2. Execute Phase 1 (Draft) of the agenda-analyst agent.",
|
|
876
1476
|
"3. If the draft phase inline-finalizes (default path), no",
|
|
877
1477
|
" downstream issues are created.",
|
|
@@ -936,6 +1536,9 @@ var finalizeAgendaSkill = {
|
|
|
936
1536
|
" - Path to the draft agenda",
|
|
937
1537
|
" (`<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md`)",
|
|
938
1538
|
" - Any late-added items to incorporate",
|
|
1539
|
+
"",
|
|
1540
|
+
...renderIssueTypeAssignmentStep(),
|
|
1541
|
+
"",
|
|
939
1542
|
"2. Execute Phase 2 (Finalize) of the agenda-analyst agent.",
|
|
940
1543
|
"",
|
|
941
1544
|
"## Output",
|
|
@@ -1227,12 +1830,111 @@ var awsCdkBundle = {
|
|
|
1227
1830
|
]
|
|
1228
1831
|
};
|
|
1229
1832
|
|
|
1833
|
+
// src/agent/bundles/issue-defaults.ts
|
|
1834
|
+
var VALID_STATUS_VALUES = [
|
|
1835
|
+
"ready",
|
|
1836
|
+
"blocked",
|
|
1837
|
+
"in-progress",
|
|
1838
|
+
"ready-for-review",
|
|
1839
|
+
"needs-attention",
|
|
1840
|
+
"done",
|
|
1841
|
+
"deferred"
|
|
1842
|
+
];
|
|
1843
|
+
var VALID_PRIORITY_VALUES = [
|
|
1844
|
+
"critical",
|
|
1845
|
+
"high",
|
|
1846
|
+
"medium",
|
|
1847
|
+
"low",
|
|
1848
|
+
"trivial"
|
|
1849
|
+
];
|
|
1850
|
+
var DEFAULT_ISSUE_STATUS = "ready";
|
|
1851
|
+
var DEFAULT_ISSUE_PRIORITY = "medium";
|
|
1852
|
+
var DEFAULT_RESOLVED_ISSUE_DEFAULTS = {
|
|
1853
|
+
defaults: {
|
|
1854
|
+
status: DEFAULT_ISSUE_STATUS,
|
|
1855
|
+
priority: DEFAULT_ISSUE_PRIORITY
|
|
1856
|
+
},
|
|
1857
|
+
overrides: {}
|
|
1858
|
+
};
|
|
1859
|
+
function resolveIssueDefaults(config) {
|
|
1860
|
+
if (config === void 0) {
|
|
1861
|
+
return DEFAULT_RESOLVED_ISSUE_DEFAULTS;
|
|
1862
|
+
}
|
|
1863
|
+
const overrides = {};
|
|
1864
|
+
for (const [phaseLabel, override] of Object.entries(config)) {
|
|
1865
|
+
assertValidPhaseLabel(phaseLabel);
|
|
1866
|
+
assertValidOverride(phaseLabel, override);
|
|
1867
|
+
overrides[phaseLabel] = {
|
|
1868
|
+
status: override.status ?? DEFAULT_ISSUE_STATUS,
|
|
1869
|
+
priority: override.priority ?? DEFAULT_ISSUE_PRIORITY
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
return {
|
|
1873
|
+
defaults: {
|
|
1874
|
+
status: DEFAULT_ISSUE_STATUS,
|
|
1875
|
+
priority: DEFAULT_ISSUE_PRIORITY
|
|
1876
|
+
},
|
|
1877
|
+
overrides
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
function validateIssueDefaultsConfig(config) {
|
|
1881
|
+
return resolveIssueDefaults(config);
|
|
1882
|
+
}
|
|
1883
|
+
function labelsForPhase(resolved, phaseLabel) {
|
|
1884
|
+
return resolved.overrides[phaseLabel] ?? resolved.defaults;
|
|
1885
|
+
}
|
|
1886
|
+
function assertValidPhaseLabel(phaseLabel) {
|
|
1887
|
+
if (typeof phaseLabel !== "string" || phaseLabel.trim() === "") {
|
|
1888
|
+
throw new Error(
|
|
1889
|
+
"AgentConfigOptions.issueDefaults: phase-label keys must be non-empty strings (e.g. `people:research`)."
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
function assertValidOverride(phaseLabel, override) {
|
|
1894
|
+
if (override === null || typeof override !== "object" || Array.isArray(override)) {
|
|
1895
|
+
throw new Error(
|
|
1896
|
+
`AgentConfigOptions.issueDefaults["${phaseLabel}"] must be an object with optional \`status\` and \`priority\` fields.`
|
|
1897
|
+
);
|
|
1898
|
+
}
|
|
1899
|
+
const { status, priority } = override;
|
|
1900
|
+
if (status === void 0 && priority === void 0) {
|
|
1901
|
+
throw new Error(
|
|
1902
|
+
`AgentConfigOptions.issueDefaults["${phaseLabel}"] must declare at least one of \`status\` or \`priority\`. Empty entries are rejected because they are almost always a typo on the field name.`
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
if (status !== void 0 && !VALID_STATUS_VALUES.includes(status)) {
|
|
1906
|
+
throw new Error(
|
|
1907
|
+
`AgentConfigOptions.issueDefaults["${phaseLabel}"].status="${status}" is not a recognised status value. Allowed values: ${VALID_STATUS_VALUES.join(", ")}.`
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
if (priority !== void 0 && !VALID_PRIORITY_VALUES.includes(priority)) {
|
|
1911
|
+
throw new Error(
|
|
1912
|
+
`AgentConfigOptions.issueDefaults["${phaseLabel}"].priority="${priority}" is not a recognised priority value. Allowed values: ${VALID_PRIORITY_VALUES.join(", ")}.`
|
|
1913
|
+
);
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1230
1917
|
// src/agent/bundles/issue-templates.ts
|
|
1231
1918
|
var DEFAULT_ISSUE_TEMPLATES_ENABLED = true;
|
|
1232
1919
|
var DEFAULT_ISSUE_TEMPLATES_PATH = "docs/src/content/docs/agents/issue-templates.md";
|
|
1233
1920
|
var DEFAULT_ISSUE_TEMPLATES_BUNDLE_PATH_PATTERNS = [".claude/agents/**/*.md", ".claude/skills/**/*.md"];
|
|
1234
1921
|
var DEFAULT_ISSUE_TEMPLATES_EMIT_CHECKER = false;
|
|
1235
1922
|
var DEFAULT_ISSUE_TEMPLATES_EMIT_STARTER = false;
|
|
1923
|
+
var ISSUE_TEMPLATES_GENERATED_SUFFIX = "-generated";
|
|
1924
|
+
function issueTemplatesGeneratedPath(templatesPath) {
|
|
1925
|
+
const slash = templatesPath.lastIndexOf("/");
|
|
1926
|
+
const dot = templatesPath.lastIndexOf(".");
|
|
1927
|
+
if (dot > slash) {
|
|
1928
|
+
return `${templatesPath.slice(0, dot)}${ISSUE_TEMPLATES_GENERATED_SUFFIX}${templatesPath.slice(dot)}`;
|
|
1929
|
+
}
|
|
1930
|
+
return `${templatesPath}${ISSUE_TEMPLATES_GENERATED_SUFFIX}`;
|
|
1931
|
+
}
|
|
1932
|
+
function issueTemplatesChildGlob(templatesPath) {
|
|
1933
|
+
const slash = templatesPath.lastIndexOf("/");
|
|
1934
|
+
const dot = templatesPath.lastIndexOf(".");
|
|
1935
|
+
const stem = dot > slash ? templatesPath.slice(0, dot) : templatesPath;
|
|
1936
|
+
return `${stem}/*.md`;
|
|
1937
|
+
}
|
|
1236
1938
|
var DEFAULT_ISSUE_TEMPLATES_REQUIRE_REFERENCE = true;
|
|
1237
1939
|
function resolveIssueTemplates(config) {
|
|
1238
1940
|
const templatesPath = config?.templatesPath ?? DEFAULT_ISSUE_TEMPLATES_PATH;
|
|
@@ -1316,7 +2018,40 @@ function renderIssueTemplatesRuleContent(it, hasDownstreamBundles = true) {
|
|
|
1316
2018
|
"issue kind appends one section; retiring a kind removes one. The",
|
|
1317
2019
|
"label taxonomy, body template shape, and placeholder conventions",
|
|
1318
2020
|
"are shared across every section.",
|
|
1319
|
-
""
|
|
2021
|
+
""
|
|
2022
|
+
];
|
|
2023
|
+
if (it.emitStarterDoc) {
|
|
2024
|
+
lines.push(
|
|
2025
|
+
"## Scaffolded Starting Point",
|
|
2026
|
+
"",
|
|
2027
|
+
"The page is hand-authored, but it does not start empty. Two files",
|
|
2028
|
+
"ship together:",
|
|
2029
|
+
"",
|
|
2030
|
+
`1. \`${it.templatesPath}\` \u2014 **written once**, then yours. Titles,`,
|
|
2031
|
+
" bodies, and the callers list are hand-authored here and never",
|
|
2032
|
+
" overwritten.",
|
|
2033
|
+
`2. \`${issueTemplatesGeneratedPath(it.templatesPath)}\` \u2014`,
|
|
2034
|
+
" **regenerated on every synth**. One",
|
|
2035
|
+
" `## Template: <phase-label>` stub per phase label the active",
|
|
2036
|
+
" bundles contribute to the label registry, with the phase label,",
|
|
2037
|
+
" the `type:<bundle>` label its owning bundle declares, and the",
|
|
2038
|
+
" configured `status:*` / `priority:*` defaults pre-filled.",
|
|
2039
|
+
"",
|
|
2040
|
+
"Only the **label set** is generated. Title and body stay",
|
|
2041
|
+
"angle-bracket placeholders, so the scaffold answers *which labels*",
|
|
2042
|
+
"without dictating *what the issue says*. Copy a stub into the",
|
|
2043
|
+
"hand-authored page, flesh out its body, and leave the label block",
|
|
2044
|
+
"as generated.",
|
|
2045
|
+
"",
|
|
2046
|
+
"The split is load-bearing. A write-once scaffold alone freezes",
|
|
2047
|
+
"every consumer on whatever skeleton shipped the day they adopted",
|
|
2048
|
+
"the convention \u2014 a new phase label minted upstream never reaches",
|
|
2049
|
+
"them. Regenerating the label half fixes that without ever",
|
|
2050
|
+
"clobbering an authored body.",
|
|
2051
|
+
""
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
lines.push(
|
|
1320
2055
|
"## Reference-Don't-Inline Rule",
|
|
1321
2056
|
"",
|
|
1322
2057
|
`Every bundle rule, agent prompt, or skill instruction that files a`,
|
|
@@ -1387,8 +2122,12 @@ function renderIssueTemplatesRuleContent(it, hasDownstreamBundles = true) {
|
|
|
1387
2122
|
" placeholders (`<Organization Name>`, `<slug>`) that match",
|
|
1388
2123
|
" existing templates. Consistency across sections lets callers",
|
|
1389
2124
|
" substitute without re-reading the body every time.",
|
|
2125
|
+
"5. **Does the recipe assign a GitHub issue type?** `gh issue",
|
|
2126
|
+
" create` cannot set it and the `type:*` label does not either, so",
|
|
2127
|
+
" every section ends with the follow-up call. An issue that skips",
|
|
2128
|
+
" it stays untyped forever.",
|
|
1390
2129
|
""
|
|
1391
|
-
|
|
2130
|
+
);
|
|
1392
2131
|
if (it.emitChecker) {
|
|
1393
2132
|
lines.push(
|
|
1394
2133
|
"## Automated Lint",
|
|
@@ -1419,6 +2158,33 @@ function renderIssueTemplatesRuleContent(it, hasDownstreamBundles = true) {
|
|
|
1419
2158
|
"(which documents the conventional `gh issue create` call shape",
|
|
1420
2159
|
"as taxonomy, not a downstream template). All other bundle",
|
|
1421
2160
|
"files in the pattern set are in scope.",
|
|
2161
|
+
"",
|
|
2162
|
+
"### Recipe label correctness",
|
|
2163
|
+
"",
|
|
2164
|
+
"A companion lint,",
|
|
2165
|
+
"`.claude/procedures/check-issue-template-labels.sh`, checks the",
|
|
2166
|
+
"recipes themselves rather than where they live. It walks the",
|
|
2167
|
+
"templates page, its router-style child pages, and the generated",
|
|
2168
|
+
"label-set companion, and fails non-zero when a",
|
|
2169
|
+
"`## Template: <phase-label>` section:",
|
|
2170
|
+
"",
|
|
2171
|
+
"- never passes `--label <phase-label>` \u2014 the heading and the",
|
|
2172
|
+
" command disagree;",
|
|
2173
|
+
"- carries no `type:*` label, more than one, or one that is not",
|
|
2174
|
+
" the `type:<bundle>` label the phase label's owning bundle",
|
|
2175
|
+
" declares;",
|
|
2176
|
+
"- has no GitHub issue-type assignment step.",
|
|
2177
|
+
"",
|
|
2178
|
+
"```bash",
|
|
2179
|
+
".claude/procedures/check-issue-template-labels.sh",
|
|
2180
|
+
"```",
|
|
2181
|
+
"",
|
|
2182
|
+
"The phase-label \u2192 type-label pairing is generated from the same",
|
|
2183
|
+
"bundle-ownership map that drives `.github/labels.yml` and the",
|
|
2184
|
+
"orchestrator's invariant sweep, so a hand-edit can never",
|
|
2185
|
+
"reintroduce a mismatch the registry has already ruled out.",
|
|
2186
|
+
"Sections whose heading matches no bundle-owned phase label are",
|
|
2187
|
+
"skipped \u2014 consumer-specific labels are deliberately not policed.",
|
|
1422
2188
|
""
|
|
1423
2189
|
);
|
|
1424
2190
|
}
|
|
@@ -1427,8 +2193,10 @@ function renderIssueTemplatesRuleContent(it, hasDownstreamBundles = true) {
|
|
|
1427
2193
|
"",
|
|
1428
2194
|
"The convention intentionally does not:",
|
|
1429
2195
|
"",
|
|
1430
|
-
"- Auto-generate
|
|
1431
|
-
"
|
|
2196
|
+
"- Auto-generate recipe **bodies**. Only the label set is",
|
|
2197
|
+
" scaffolded, because labels are derivable from the bundle",
|
|
2198
|
+
" registry and bodies are not \u2014 repo-specific objectives,",
|
|
2199
|
+
" acceptance criteria, and callers lists stay hand-authored.",
|
|
1432
2200
|
"- Prescribe a fixed body shape across templates. Each section",
|
|
1433
2201
|
" may carry its own `## Acceptance Criteria`, `## Scope Size`,",
|
|
1434
2202
|
" or `## Output Path` fields as the downstream agent requires;",
|
|
@@ -1459,7 +2227,8 @@ function renderIssueTemplatesBundleHook(it, bundleLabel) {
|
|
|
1459
2227
|
"as an inline template vs. a prose mention."
|
|
1460
2228
|
].join("\n");
|
|
1461
2229
|
}
|
|
1462
|
-
function renderIssueTemplatesStarterPage(
|
|
2230
|
+
function renderIssueTemplatesStarterPage(it) {
|
|
2231
|
+
const generatedLink = `./${basename(issueTemplatesGeneratedPath(it.templatesPath))}`;
|
|
1463
2232
|
return [
|
|
1464
2233
|
"---",
|
|
1465
2234
|
"title: Issue Templates",
|
|
@@ -1481,11 +2250,33 @@ function renderIssueTemplatesStarterPage(_it) {
|
|
|
1481
2250
|
"`status:*` label from the conventions documented in the",
|
|
1482
2251
|
"`issue-label-conventions` rule.",
|
|
1483
2252
|
"",
|
|
2253
|
+
"Every recipe also ends with a **GitHub issue type** assignment.",
|
|
2254
|
+
"`gh issue create` cannot set the issue type, so it takes a second",
|
|
2255
|
+
"call \u2014 an issue that skips it stays untyped forever. Derive the type",
|
|
2256
|
+
"from the title prefix (`epic:` \u2192 Epic, `feat:` \u2192 Feature, `fix:` \u2192",
|
|
2257
|
+
"Bug, everything else \u2014 including every bundle-phase prefix \u2014 \u2192",
|
|
2258
|
+
"Task); see **Assigning the GitHub issue type** in the",
|
|
2259
|
+
"`issue-conventions` rule for the command and its fallback.",
|
|
2260
|
+
"",
|
|
1484
2261
|
"Before creating any profile-style issue (people, companies,",
|
|
1485
2262
|
"software), run the duplicate check documented in the owning",
|
|
1486
2263
|
"bundle's rule \u2014 the issue-templates page is a recipe catalogue,",
|
|
1487
2264
|
"not a duplicate-check layer.",
|
|
1488
2265
|
"",
|
|
2266
|
+
"## Generated label sets",
|
|
2267
|
+
"",
|
|
2268
|
+
`[Generated Issue-Template Label Sets](${generatedLink}) carries one`,
|
|
2269
|
+
"correct-by-construction stub per phase label the active bundles",
|
|
2270
|
+
"emit \u2014 the phase label paired with the `type:<bundle>` label its",
|
|
2271
|
+
"owning bundle declares, plus the configured `status:*` /",
|
|
2272
|
+
"`priority:*` defaults. That page regenerates on every `projen` run,",
|
|
2273
|
+
"so it never goes stale as phase labels come and go.",
|
|
2274
|
+
"",
|
|
2275
|
+
"This page is the opposite: written once, then owned by you. Copy a",
|
|
2276
|
+
"stub across, flesh out its title and body here, and leave the label",
|
|
2277
|
+
"block exactly as generated \u2014 the label-consistency lint holds both",
|
|
2278
|
+
"copies to the same pairing.",
|
|
2279
|
+
"",
|
|
1489
2280
|
"## Template: example-phase",
|
|
1490
2281
|
"",
|
|
1491
2282
|
"Replace this example with the real templates for this repo. Each",
|
|
@@ -1515,9 +2306,125 @@ function renderIssueTemplatesStarterPage(_it) {
|
|
|
1515
2306
|
"- [ ] <criterion 1>",
|
|
1516
2307
|
"- [ ] <criterion 2>",
|
|
1517
2308
|
'"',
|
|
2309
|
+
"```",
|
|
2310
|
+
"",
|
|
2311
|
+
"Then assign the GitHub issue type (`Task` for a phase-labelled",
|
|
2312
|
+
"title):",
|
|
2313
|
+
"",
|
|
2314
|
+
"```bash",
|
|
2315
|
+
`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${DEFAULT_GITHUB_ISSUE_TYPE}`,
|
|
1518
2316
|
"```"
|
|
1519
2317
|
].join("\n");
|
|
1520
2318
|
}
|
|
2319
|
+
function collectIssueTemplateRecipeStubs(bundles, issueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS) {
|
|
2320
|
+
const stubs = /* @__PURE__ */ new Map();
|
|
2321
|
+
for (const bundle of bundles) {
|
|
2322
|
+
for (const label of bundle.labels ?? []) {
|
|
2323
|
+
const typeLabel = typeLabelForPhaseLabel(label.name);
|
|
2324
|
+
if (typeLabel === void 0) {
|
|
2325
|
+
continue;
|
|
2326
|
+
}
|
|
2327
|
+
if (stubs.has(label.name)) {
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
const defaults = labelsForPhase(issueDefaults, label.name);
|
|
2331
|
+
stubs.set(label.name, {
|
|
2332
|
+
phaseLabel: label.name,
|
|
2333
|
+
typeLabel,
|
|
2334
|
+
bundleName: bundle.name,
|
|
2335
|
+
description: label.description ?? "",
|
|
2336
|
+
status: defaults.status,
|
|
2337
|
+
priority: defaults.priority,
|
|
2338
|
+
issueType: githubIssueTypeForTitle(`${label.name}: placeholder`)
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return [...stubs.values()].sort(
|
|
2343
|
+
(a, b) => a.phaseLabel.localeCompare(b.phaseLabel)
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
function renderIssueTemplatesGeneratedPage(it, stubs) {
|
|
2347
|
+
const lines = [
|
|
2348
|
+
"---",
|
|
2349
|
+
"title: Generated Issue-Template Label Sets",
|
|
2350
|
+
"description: Auto-generated label-correct gh issue create stubs \u2014 one per phase label.",
|
|
2351
|
+
"---",
|
|
2352
|
+
"",
|
|
2353
|
+
"**Generated file \u2014 do not edit.** Every section below is",
|
|
2354
|
+
"regenerated from the active bundle set on each `projen` run; hand",
|
|
2355
|
+
"edits are overwritten. The hand-authored recipes live in",
|
|
2356
|
+
`[the issue-templates page](./${basename(it.templatesPath)}) \u2014 this`,
|
|
2357
|
+
"page exists so the **label half** of every recipe stays",
|
|
2358
|
+
"correct-by-construction as phase labels come and go.",
|
|
2359
|
+
"",
|
|
2360
|
+
"## How to use",
|
|
2361
|
+
"",
|
|
2362
|
+
"Each section carries the exact label set the phase-label invariant",
|
|
2363
|
+
"requires: the phase label itself, the `type:<bundle>` label its",
|
|
2364
|
+
"owning bundle declares, and the configured `status:*` / `priority:*`",
|
|
2365
|
+
"defaults for that phase. Title and body are placeholders \u2014 copy the",
|
|
2366
|
+
"stub into the hand-authored templates page and flesh out the body",
|
|
2367
|
+
"there, or run it as-is when no repo-specific body exists yet.",
|
|
2368
|
+
"",
|
|
2369
|
+
"Every stub ends with the **GitHub issue type** assignment. `gh issue",
|
|
2370
|
+
"create` cannot set the issue type and the `type:*` label does not",
|
|
2371
|
+
"set it either, so an issue that skips the follow-up call stays",
|
|
2372
|
+
"untyped forever. See **Assigning the GitHub issue type** in the",
|
|
2373
|
+
"`issue-conventions` rule for the no-helper fallback.",
|
|
2374
|
+
""
|
|
2375
|
+
];
|
|
2376
|
+
if (stubs.length === 0) {
|
|
2377
|
+
lines.push(
|
|
2378
|
+
"## No phase labels",
|
|
2379
|
+
"",
|
|
2380
|
+
"No active bundle contributes a phase label, so there is nothing to",
|
|
2381
|
+
"scaffold. Enable a phased-pipeline bundle (or drop it from",
|
|
2382
|
+
"`excludeBundles`) and re-run `projen`."
|
|
2383
|
+
);
|
|
2384
|
+
return lines.join("\n");
|
|
2385
|
+
}
|
|
2386
|
+
for (const stub of stubs) {
|
|
2387
|
+
lines.push(
|
|
2388
|
+
`## Template: ${stub.phaseLabel}`,
|
|
2389
|
+
"",
|
|
2390
|
+
...stub.description === "" ? [] : [stub.description, ""],
|
|
2391
|
+
`**Owning bundle:** \`${stub.bundleName}\` \u2014 **required type label:**`,
|
|
2392
|
+
`\`${stub.typeLabel}\` (paired by the bundle-ownership map).`,
|
|
2393
|
+
"",
|
|
2394
|
+
"**Callers:** <name the bundles and agents that file this issue>",
|
|
2395
|
+
"",
|
|
2396
|
+
"```bash",
|
|
2397
|
+
"gh issue create \\",
|
|
2398
|
+
` --title "${stub.phaseLabel}: <short description>" \\`,
|
|
2399
|
+
` --label "${stub.typeLabel}" \\`,
|
|
2400
|
+
` --label "${stub.phaseLabel}" \\`,
|
|
2401
|
+
` --label "priority:${stub.priority}" \\`,
|
|
2402
|
+
` --label "status:${stub.status}" \\`,
|
|
2403
|
+
' --body "## Objective',
|
|
2404
|
+
"",
|
|
2405
|
+
"<1-3 sentences describing the work>.",
|
|
2406
|
+
"",
|
|
2407
|
+
"## Context",
|
|
2408
|
+
"",
|
|
2409
|
+
"- **Discovered in:** <source description> (#<parent-issue>)",
|
|
2410
|
+
"",
|
|
2411
|
+
"## Acceptance Criteria",
|
|
2412
|
+
"",
|
|
2413
|
+
"- [ ] <criterion 1>",
|
|
2414
|
+
'"',
|
|
2415
|
+
"```",
|
|
2416
|
+
"",
|
|
2417
|
+
`Then assign the GitHub issue type (\`${stub.issueType}\`):`,
|
|
2418
|
+
"",
|
|
2419
|
+
"```bash",
|
|
2420
|
+
`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${stub.issueType}`,
|
|
2421
|
+
"```",
|
|
2422
|
+
""
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
lines.pop();
|
|
2426
|
+
return lines.join("\n");
|
|
2427
|
+
}
|
|
1521
2428
|
function renderIssueTemplatesCheckerScript(it) {
|
|
1522
2429
|
const patternsLiteral = it.bundlePathPatterns.map((p) => ` ${JSON.stringify(p)}`).join("\n");
|
|
1523
2430
|
return [
|
|
@@ -1706,6 +2613,157 @@ function renderIssueTemplatesCheckerScript(it) {
|
|
|
1706
2613
|
"exit 0"
|
|
1707
2614
|
].join("\n");
|
|
1708
2615
|
}
|
|
2616
|
+
function renderIssueTemplateLabelsCheckerScript(it) {
|
|
2617
|
+
const generatedPath = issueTemplatesGeneratedPath(it.templatesPath);
|
|
2618
|
+
const childGlob = issueTemplatesChildGlob(it.templatesPath);
|
|
2619
|
+
return [
|
|
2620
|
+
"#!/usr/bin/env bash",
|
|
2621
|
+
"# check-issue-template-labels.sh \u2014 Enforce recipe label correctness.",
|
|
2622
|
+
"#",
|
|
2623
|
+
"# Usage:",
|
|
2624
|
+
"# .claude/procedures/check-issue-template-labels.sh [<file>...]",
|
|
2625
|
+
"#",
|
|
2626
|
+
"# With no arguments the lint walks the templates page, its",
|
|
2627
|
+
"# router-style child pages, and the generated label-set companion.",
|
|
2628
|
+
"# Positional arguments override that default set.",
|
|
2629
|
+
"#",
|
|
2630
|
+
"# For every `## Template: <phase-label>` section it asserts the",
|
|
2631
|
+
"# recipe passes the heading's phase label, carries exactly one",
|
|
2632
|
+
"# `type:*` label matching the phase-label invariant, and assigns a",
|
|
2633
|
+
"# GitHub issue type. Sections whose heading matches no bundle-owned",
|
|
2634
|
+
"# phase label are skipped \u2014 unrecognised labels are consumer-",
|
|
2635
|
+
"# specific and deliberately not policed.",
|
|
2636
|
+
"#",
|
|
2637
|
+
"# The resolver below is generated from the canonical bundle-",
|
|
2638
|
+
"# ownership map \u2014 do not edit by hand; regenerate via",
|
|
2639
|
+
"# `pnpm exec projen`.",
|
|
2640
|
+
"",
|
|
2641
|
+
"set -uo pipefail",
|
|
2642
|
+
"",
|
|
2643
|
+
"err() {",
|
|
2644
|
+
' printf "check-issue-template-labels.sh: %s\\n" "$*" >&2',
|
|
2645
|
+
"}",
|
|
2646
|
+
"",
|
|
2647
|
+
renderPhaseTypeInvariantShellHelpers(),
|
|
2648
|
+
"",
|
|
2649
|
+
`templates_path=${JSON.stringify(it.templatesPath)}`,
|
|
2650
|
+
`generated_path=${JSON.stringify(generatedPath)}`,
|
|
2651
|
+
`child_glob=${JSON.stringify(childGlob)}`,
|
|
2652
|
+
"",
|
|
2653
|
+
"# Emit one TAB-separated record per `## Template:` section:",
|
|
2654
|
+
"# <file>\\t<line>\\t<phase-label>\\t<comma-joined labels>\\t<0|1 typed>",
|
|
2655
|
+
"# Quote characters are folded to spaces up front so a recipe written",
|
|
2656
|
+
"# with single quotes, double quotes, or none at all parses the same.",
|
|
2657
|
+
"# Fenced blocks are tracked so the `## Objective` heading inside a",
|
|
2658
|
+
"# recipe's --body string never reads as the end of the section.",
|
|
2659
|
+
"scan_file() {",
|
|
2660
|
+
' local file="$1"',
|
|
2661
|
+
` tr '\\042\\047' ' ' < "$file" | awk -v FNAME="$file" '`,
|
|
2662
|
+
" function flush() {",
|
|
2663
|
+
' if (phase != "") {',
|
|
2664
|
+
' printf "%s\\t%d\\t%s\\t%s\\t%d\\n", FNAME, start, phase, labels, hastype;',
|
|
2665
|
+
" }",
|
|
2666
|
+
' phase = ""; labels = ""; hastype = 0;',
|
|
2667
|
+
" }",
|
|
2668
|
+
" {",
|
|
2669
|
+
" if ($0 ~ /^[ \\t]*```/) {",
|
|
2670
|
+
" fence = 1 - fence;",
|
|
2671
|
+
' } else if (fence == 0 && index($0, "## ") == 1) {',
|
|
2672
|
+
" flush();",
|
|
2673
|
+
' if (index($0, "## Template: ") == 1) {',
|
|
2674
|
+
" phase = substr($0, 14);",
|
|
2675
|
+
' gsub(/[ \\t`]/, "", phase);',
|
|
2676
|
+
" start = NR;",
|
|
2677
|
+
" }",
|
|
2678
|
+
" next;",
|
|
2679
|
+
" }",
|
|
2680
|
+
' if (phase == "") next;',
|
|
2681
|
+
" if ($0 ~ /set-issue-type\\.sh/ || $0 ~ /updateIssueIssueType/) {",
|
|
2682
|
+
" hastype = 1;",
|
|
2683
|
+
" }",
|
|
2684
|
+
" line = $0;",
|
|
2685
|
+
" while (match(line, /--label[ \\t]+[^ \\t]+/)) {",
|
|
2686
|
+
" tok = substr(line, RSTART, RLENGTH);",
|
|
2687
|
+
" line = substr(line, RSTART + RLENGTH);",
|
|
2688
|
+
' sub(/^--label[ \\t]+/, "", tok);',
|
|
2689
|
+
' gsub(/[\\\\`]/, "", tok);',
|
|
2690
|
+
' labels = labels tok ",";',
|
|
2691
|
+
" }",
|
|
2692
|
+
" }",
|
|
2693
|
+
" END { flush(); }",
|
|
2694
|
+
" '",
|
|
2695
|
+
"}",
|
|
2696
|
+
"",
|
|
2697
|
+
"# Collect the file list: positional args override the default set.",
|
|
2698
|
+
"files=()",
|
|
2699
|
+
"if [[ $# -gt 0 ]]; then",
|
|
2700
|
+
' files=("$@")',
|
|
2701
|
+
"else",
|
|
2702
|
+
' [[ -f "$templates_path" ]] && files+=("$templates_path")',
|
|
2703
|
+
' [[ -f "$generated_path" ]] && files+=("$generated_path")',
|
|
2704
|
+
" for child in $child_glob; do",
|
|
2705
|
+
' [[ -f "$child" ]] && files+=("$child")',
|
|
2706
|
+
" done",
|
|
2707
|
+
"fi",
|
|
2708
|
+
"",
|
|
2709
|
+
"if [[ ${#files[@]} -eq 0 ]]; then",
|
|
2710
|
+
" exit 0",
|
|
2711
|
+
"fi",
|
|
2712
|
+
"",
|
|
2713
|
+
"violations=()",
|
|
2714
|
+
"checked=0",
|
|
2715
|
+
"",
|
|
2716
|
+
'for file in "${files[@]}"; do',
|
|
2717
|
+
' [[ -f "$file" ]] || continue',
|
|
2718
|
+
" while IFS=$'\\t' read -r rec_file rec_line phase labels hastype; do",
|
|
2719
|
+
' [[ -z "$phase" ]] && continue',
|
|
2720
|
+
' required=$(phase_label_type_of "$phase")',
|
|
2721
|
+
' [[ -z "$required" ]] && continue',
|
|
2722
|
+
" checked=$(( checked + 1 ))",
|
|
2723
|
+
' case ",${labels}" in',
|
|
2724
|
+
' *",${phase},"*) ;;',
|
|
2725
|
+
` *) violations+=("$rec_file:$rec_line: recipe for '$phase' never passes --label $phase") ;;`,
|
|
2726
|
+
" esac",
|
|
2727
|
+
' type_labels=""',
|
|
2728
|
+
" type_count=0",
|
|
2729
|
+
' for entry in $(printf "%s" "$labels" | tr , " "); do',
|
|
2730
|
+
' case "$entry" in',
|
|
2731
|
+
" type:*)",
|
|
2732
|
+
' type_labels="${type_labels}${entry} "',
|
|
2733
|
+
" type_count=$(( type_count + 1 ))",
|
|
2734
|
+
" ;;",
|
|
2735
|
+
" esac",
|
|
2736
|
+
" done",
|
|
2737
|
+
' if [[ "$type_count" -eq 0 ]]; then',
|
|
2738
|
+
` violations+=("$rec_file:$rec_line: recipe for '$phase' carries no type:* label (expected $required)")`,
|
|
2739
|
+
' elif [[ "$type_count" -gt 1 ]]; then',
|
|
2740
|
+
" violations+=(\"$rec_file:$rec_line: recipe for '$phase' carries ${type_count} type:* labels (${type_labels% }); exactly one is allowed\")",
|
|
2741
|
+
' elif [[ "${type_labels% }" != "$required" ]]; then',
|
|
2742
|
+
` violations+=("$rec_file:$rec_line: recipe for '$phase' carries \${type_labels% } but the phase label requires $required")`,
|
|
2743
|
+
" fi",
|
|
2744
|
+
' if [[ "$hastype" != "1" ]]; then',
|
|
2745
|
+
` violations+=("$rec_file:$rec_line: recipe for '$phase' has no GitHub issue-type assignment step")`,
|
|
2746
|
+
" fi",
|
|
2747
|
+
' done < <(scan_file "$file")',
|
|
2748
|
+
"done",
|
|
2749
|
+
"",
|
|
2750
|
+
"if [[ ${#violations[@]} -gt 0 ]]; then",
|
|
2751
|
+
' err "issue-template recipes disagree with the phase-label invariant:"',
|
|
2752
|
+
' for v in "${violations[@]}"; do',
|
|
2753
|
+
' err " - $v"',
|
|
2754
|
+
" done",
|
|
2755
|
+
` err "each '## Template: <phase-label>' recipe must pass its own phase label, exactly one matching type:<bundle> label, and a set-issue-type.sh (or updateIssueIssueType) step"`,
|
|
2756
|
+
" exit 1",
|
|
2757
|
+
"fi",
|
|
2758
|
+
"",
|
|
2759
|
+
'printf "check-issue-template-labels.sh: %d recipe(s) OK\\n" "$checked"',
|
|
2760
|
+
"exit 0"
|
|
2761
|
+
].join("\n");
|
|
2762
|
+
}
|
|
2763
|
+
function basename(path8) {
|
|
2764
|
+
const slash = path8.lastIndexOf("/");
|
|
2765
|
+
return slash === -1 ? path8 : path8.slice(slash + 1);
|
|
2766
|
+
}
|
|
1709
2767
|
function assertValidTemplatesPath(value) {
|
|
1710
2768
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1711
2769
|
throw new Error(
|
|
@@ -4619,16 +5677,7 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
|
|
|
4619
5677
|
"| `release:` | Release preparation, version bumps |",
|
|
4620
5678
|
"| `hotfix:` | Urgent production fixes |",
|
|
4621
5679
|
"",
|
|
4622
|
-
|
|
4623
|
-
"",
|
|
4624
|
-
"When creating issues, always assign the appropriate **GitHub issue type** based on the title prefix:",
|
|
4625
|
-
"",
|
|
4626
|
-
"| Prefix | GitHub Issue Type |",
|
|
4627
|
-
"|--------|------------------|",
|
|
4628
|
-
"| `epic:` | Epic |",
|
|
4629
|
-
"| `feat:` | Feature |",
|
|
4630
|
-
"| `fix:` | Bug |",
|
|
4631
|
-
"| `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` | Task |",
|
|
5680
|
+
...renderGithubIssueTypeSectionLines(),
|
|
4632
5681
|
"",
|
|
4633
5682
|
"## Prerequisite Issues",
|
|
4634
5683
|
"",
|
|
@@ -4717,90 +5766,6 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
|
|
|
4717
5766
|
}
|
|
4718
5767
|
var baseBundle = buildBaseBundle();
|
|
4719
5768
|
|
|
4720
|
-
// src/agent/bundles/issue-defaults.ts
|
|
4721
|
-
var VALID_STATUS_VALUES = [
|
|
4722
|
-
"ready",
|
|
4723
|
-
"blocked",
|
|
4724
|
-
"in-progress",
|
|
4725
|
-
"ready-for-review",
|
|
4726
|
-
"needs-attention",
|
|
4727
|
-
"done",
|
|
4728
|
-
"deferred"
|
|
4729
|
-
];
|
|
4730
|
-
var VALID_PRIORITY_VALUES = [
|
|
4731
|
-
"critical",
|
|
4732
|
-
"high",
|
|
4733
|
-
"medium",
|
|
4734
|
-
"low",
|
|
4735
|
-
"trivial"
|
|
4736
|
-
];
|
|
4737
|
-
var DEFAULT_ISSUE_STATUS = "ready";
|
|
4738
|
-
var DEFAULT_ISSUE_PRIORITY = "medium";
|
|
4739
|
-
var DEFAULT_RESOLVED_ISSUE_DEFAULTS = {
|
|
4740
|
-
defaults: {
|
|
4741
|
-
status: DEFAULT_ISSUE_STATUS,
|
|
4742
|
-
priority: DEFAULT_ISSUE_PRIORITY
|
|
4743
|
-
},
|
|
4744
|
-
overrides: {}
|
|
4745
|
-
};
|
|
4746
|
-
function resolveIssueDefaults(config) {
|
|
4747
|
-
if (config === void 0) {
|
|
4748
|
-
return DEFAULT_RESOLVED_ISSUE_DEFAULTS;
|
|
4749
|
-
}
|
|
4750
|
-
const overrides = {};
|
|
4751
|
-
for (const [phaseLabel, override] of Object.entries(config)) {
|
|
4752
|
-
assertValidPhaseLabel(phaseLabel);
|
|
4753
|
-
assertValidOverride(phaseLabel, override);
|
|
4754
|
-
overrides[phaseLabel] = {
|
|
4755
|
-
status: override.status ?? DEFAULT_ISSUE_STATUS,
|
|
4756
|
-
priority: override.priority ?? DEFAULT_ISSUE_PRIORITY
|
|
4757
|
-
};
|
|
4758
|
-
}
|
|
4759
|
-
return {
|
|
4760
|
-
defaults: {
|
|
4761
|
-
status: DEFAULT_ISSUE_STATUS,
|
|
4762
|
-
priority: DEFAULT_ISSUE_PRIORITY
|
|
4763
|
-
},
|
|
4764
|
-
overrides
|
|
4765
|
-
};
|
|
4766
|
-
}
|
|
4767
|
-
function validateIssueDefaultsConfig(config) {
|
|
4768
|
-
return resolveIssueDefaults(config);
|
|
4769
|
-
}
|
|
4770
|
-
function labelsForPhase(resolved, phaseLabel) {
|
|
4771
|
-
return resolved.overrides[phaseLabel] ?? resolved.defaults;
|
|
4772
|
-
}
|
|
4773
|
-
function assertValidPhaseLabel(phaseLabel) {
|
|
4774
|
-
if (typeof phaseLabel !== "string" || phaseLabel.trim() === "") {
|
|
4775
|
-
throw new Error(
|
|
4776
|
-
"AgentConfigOptions.issueDefaults: phase-label keys must be non-empty strings (e.g. `people:research`)."
|
|
4777
|
-
);
|
|
4778
|
-
}
|
|
4779
|
-
}
|
|
4780
|
-
function assertValidOverride(phaseLabel, override) {
|
|
4781
|
-
if (override === null || typeof override !== "object" || Array.isArray(override)) {
|
|
4782
|
-
throw new Error(
|
|
4783
|
-
`AgentConfigOptions.issueDefaults["${phaseLabel}"] must be an object with optional \`status\` and \`priority\` fields.`
|
|
4784
|
-
);
|
|
4785
|
-
}
|
|
4786
|
-
const { status, priority } = override;
|
|
4787
|
-
if (status === void 0 && priority === void 0) {
|
|
4788
|
-
throw new Error(
|
|
4789
|
-
`AgentConfigOptions.issueDefaults["${phaseLabel}"] must declare at least one of \`status\` or \`priority\`. Empty entries are rejected because they are almost always a typo on the field name.`
|
|
4790
|
-
);
|
|
4791
|
-
}
|
|
4792
|
-
if (status !== void 0 && !VALID_STATUS_VALUES.includes(status)) {
|
|
4793
|
-
throw new Error(
|
|
4794
|
-
`AgentConfigOptions.issueDefaults["${phaseLabel}"].status="${status}" is not a recognised status value. Allowed values: ${VALID_STATUS_VALUES.join(", ")}.`
|
|
4795
|
-
);
|
|
4796
|
-
}
|
|
4797
|
-
if (priority !== void 0 && !VALID_PRIORITY_VALUES.includes(priority)) {
|
|
4798
|
-
throw new Error(
|
|
4799
|
-
`AgentConfigOptions.issueDefaults["${phaseLabel}"].priority="${priority}" is not a recognised priority value. Allowed values: ${VALID_PRIORITY_VALUES.join(", ")}.`
|
|
4800
|
-
);
|
|
4801
|
-
}
|
|
4802
|
-
}
|
|
4803
|
-
|
|
4804
5769
|
// src/agent/bundles/bcm-writer.ts
|
|
4805
5770
|
function buildBcmWriterSubAgent(paths, issueDefaults) {
|
|
4806
5771
|
return {
|
|
@@ -5318,6 +6283,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
|
|
|
5318
6283
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
5319
6284
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
5320
6285
|
"",
|
|
6286
|
+
...renderIssueTypeAssignmentStep(),
|
|
6287
|
+
"",
|
|
5321
6288
|
" **Unfamiliar company (enabling vendor, partner, competitor).**",
|
|
5322
6289
|
" Hand off to the `company-profile` bundle by creating a",
|
|
5323
6290
|
" `company:research` issue. The issue must carry:",
|
|
@@ -5327,6 +6294,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
|
|
|
5327
6294
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
5328
6295
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
5329
6296
|
"",
|
|
6297
|
+
...renderIssueTypeAssignmentStep(),
|
|
6298
|
+
"",
|
|
5330
6299
|
" **Missing research topic (value stream, market sizing, etc.).**",
|
|
5331
6300
|
" Hand off to the `research-pipeline` bundle by creating a",
|
|
5332
6301
|
" `research:scope` issue. The issue must carry:",
|
|
@@ -5336,6 +6305,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
|
|
|
5336
6305
|
` - \`priority:${labelsForPhase(issueDefaults, "research:scope").priority}\``,
|
|
5337
6306
|
` - \`status:${labelsForPhase(issueDefaults, "research:scope").status}\``,
|
|
5338
6307
|
"",
|
|
6308
|
+
...renderIssueTypeAssignmentStep(),
|
|
6309
|
+
"",
|
|
5339
6310
|
" This phase assumes the `people-profile`, `company-profile`, and",
|
|
5340
6311
|
" `research-pipeline` bundles are enabled in the consuming project.",
|
|
5341
6312
|
" If a bundle is not enabled, flag the connect issue with",
|
|
@@ -5458,6 +6429,8 @@ function buildWriteBcmSkill(paths, issueDefaults) {
|
|
|
5458
6429
|
` \`priority:${labelsForPhase(issueDefaults, "bcm:outline").priority}\`, and \`status:${labelsForPhase(issueDefaults, "bcm:outline").status}\`. Body must include the`,
|
|
5459
6430
|
" verbatim capability name and any overrides.",
|
|
5460
6431
|
"",
|
|
6432
|
+
"",
|
|
6433
|
+
...renderIssueTypeAssignmentStep(),
|
|
5461
6434
|
"2. Execute Phase 1 (Outline) of the bcm-writer agent.",
|
|
5462
6435
|
"",
|
|
5463
6436
|
"3. Phase 1 creates a `bcm:scaffold` issue, which Phase 2 follows with",
|
|
@@ -6744,6 +7717,8 @@ function buildScanBusinessModelsSkill(paths, issueDefaults) {
|
|
|
6744
7717
|
"1. Create a `business-models:scan` issue with `type:business-model`,",
|
|
6745
7718
|
` \`priority:${labelsForPhase(issueDefaults, "business-models:scan").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:scan").status}\`. The body must include the`,
|
|
6746
7719
|
" industry slug, the source plan path (if any), and any overrides.",
|
|
7720
|
+
"",
|
|
7721
|
+
...renderIssueTypeAssignmentStep(),
|
|
6747
7722
|
"2. Execute Phase 1 (Scan) of the business-models-analyst agent.",
|
|
6748
7723
|
"3. Phase 1 creates one `business-models:canvas` issue per in-scope",
|
|
6749
7724
|
" segment. Each canvas issue declares its `Depends on:`",
|
|
@@ -6818,6 +7793,8 @@ function buildCanvasBusinessModelSkill(paths, issueDefaults) {
|
|
|
6818
7793
|
` \`type:business-model\`, \`priority:${labelsForPhase(issueDefaults, "business-models:canvas").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:canvas").status}\`.`,
|
|
6819
7794
|
" The body must include the industry slug, segment slug, and any",
|
|
6820
7795
|
" scan-report reference.",
|
|
7796
|
+
"",
|
|
7797
|
+
...renderIssueTypeAssignmentStep(),
|
|
6821
7798
|
"2. Execute Phase 2 (Canvas) of the business-models-analyst agent.",
|
|
6822
7799
|
"3. Phase 2 writes the nine-block canvas and creates a",
|
|
6823
7800
|
" `business-models:complete` issue for the downstream Phase 3.",
|
|
@@ -6877,6 +7854,8 @@ function buildCompleteBusinessModelSkill(paths, issueDefaults) {
|
|
|
6877
7854
|
"1. Create a `business-models:complete` issue with",
|
|
6878
7855
|
` \`type:business-model\`, \`priority:${labelsForPhase(issueDefaults, "business-models:complete").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:complete").status}\`.`,
|
|
6879
7856
|
" Body must include the canvas document path.",
|
|
7857
|
+
"",
|
|
7858
|
+
...renderIssueTypeAssignmentStep(),
|
|
6880
7859
|
"2. Execute Phase 3 (Complete) of the business-models-analyst agent.",
|
|
6881
7860
|
"",
|
|
6882
7861
|
"## Output",
|
|
@@ -7401,6 +8380,8 @@ function buildCompanyProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
7401
8380
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
7402
8381
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
7403
8382
|
"",
|
|
8383
|
+
...renderIssueTypeAssignmentStep(),
|
|
8384
|
+
"",
|
|
7404
8385
|
" The issue body must include:",
|
|
7405
8386
|
" - A **discovery source** line naming this company profile",
|
|
7406
8387
|
" (`Discovered while profiling: <company name>`)",
|
|
@@ -7418,6 +8399,8 @@ function buildCompanyProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
7418
8399
|
` - \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\``,
|
|
7419
8400
|
` - \`status:${labelsForPhase(issueDefaults, "software:research").status}\``,
|
|
7420
8401
|
"",
|
|
8402
|
+
...renderIssueTypeAssignmentStep(),
|
|
8403
|
+
"",
|
|
7421
8404
|
" The issue body must include:",
|
|
7422
8405
|
" - A **discovery source** line naming this company profile",
|
|
7423
8406
|
" (`Discovered while profiling: <company name>`)",
|
|
@@ -7969,6 +8952,8 @@ function buildProfileCompanySkill(paths, issueDefaults) {
|
|
|
7969
8952
|
"1. Create a `company:research` issue with `type:company-profile`,",
|
|
7970
8953
|
` \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:research").status}\`. Body must include the`,
|
|
7971
8954
|
" company name, selected type, framing, and any overrides.",
|
|
8955
|
+
"",
|
|
8956
|
+
...renderIssueTypeAssignmentStep(),
|
|
7972
8957
|
"2. Execute Phase 1 (Research) of the company-profile-analyst agent.",
|
|
7973
8958
|
"3. Phase 1 creates the `company:draft` issue. Phase 2 may create a",
|
|
7974
8959
|
" `company:followup` issue **and** a `company:match` issue. Each",
|
|
@@ -8043,6 +9028,8 @@ function buildMatchCompanySkill(paths, issueDefaults) {
|
|
|
8043
9028
|
"1. Create a `company:match` issue with `type:company-profile`,",
|
|
8044
9029
|
` \`priority:${labelsForPhase(issueDefaults, "company:match").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:match").status}\`. Body must include the`,
|
|
8045
9030
|
" profile path and any overrides.",
|
|
9031
|
+
"",
|
|
9032
|
+
...renderIssueTypeAssignmentStep(),
|
|
8046
9033
|
"2. Execute Phase 4 (Match) of the company-profile-analyst agent.",
|
|
8047
9034
|
"",
|
|
8048
9035
|
"## Output",
|
|
@@ -8116,6 +9103,8 @@ function buildRefreshCompanySkill(paths, issueDefaults) {
|
|
|
8116
9103
|
"1. Create a `company:refresh` issue with `type:company-profile`,",
|
|
8117
9104
|
` \`priority:${labelsForPhase(issueDefaults, "company:refresh").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:refresh").status}\`. Body must include the`,
|
|
8118
9105
|
" profile path and any overrides.",
|
|
9106
|
+
"",
|
|
9107
|
+
...renderIssueTypeAssignmentStep(),
|
|
8119
9108
|
"2. Execute Phase 5 (Refresh) of the company-profile-analyst agent.",
|
|
8120
9109
|
"",
|
|
8121
9110
|
"## Output",
|
|
@@ -8189,6 +9178,8 @@ function buildAnalyzeSegmentSkill(paths, issueDefaults) {
|
|
|
8189
9178
|
"1. Create a `company:analyze` issue with `type:company-profile`,",
|
|
8190
9179
|
` \`priority:${labelsForPhase(issueDefaults, "company:analyze").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:analyze").status}\`. Body must include the`,
|
|
8191
9180
|
" segment slug and any overrides.",
|
|
9181
|
+
"",
|
|
9182
|
+
...renderIssueTypeAssignmentStep(),
|
|
8192
9183
|
"2. Execute Phase 6 (Analyze) of the company-profile-analyst agent.",
|
|
8193
9184
|
"",
|
|
8194
9185
|
"## Output",
|
|
@@ -8777,6 +9768,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
8777
9768
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
8778
9769
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
8779
9770
|
"",
|
|
9771
|
+
...renderIssueTypeAssignmentStep(),
|
|
9772
|
+
"",
|
|
8780
9773
|
"9. **Create `people:research` issues** for notable contacts",
|
|
8781
9774
|
" (economic buyers, technical buyers, user champions) surfaced in",
|
|
8782
9775
|
" sources. Keep the list small \u2014 at most three individuals per",
|
|
@@ -8788,6 +9781,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
8788
9781
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
8789
9782
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
8790
9783
|
"",
|
|
9784
|
+
...renderIssueTypeAssignmentStep(),
|
|
9785
|
+
"",
|
|
8791
9786
|
"10. **Verify all handoffs were created** before committing.",
|
|
8792
9787
|
"",
|
|
8793
9788
|
"11. **Commit and push** the archetype page. Close the profile issue.",
|
|
@@ -8889,6 +9884,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
8889
9884
|
` - \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\``,
|
|
8890
9885
|
` - \`status:${labelsForPhase(issueDefaults, "req:scan").status}\``,
|
|
8891
9886
|
"",
|
|
9887
|
+
...renderIssueTypeAssignmentStep(),
|
|
9888
|
+
"",
|
|
8892
9889
|
" The body must also:",
|
|
8893
9890
|
" - Link back to the archetype page and the competitor page",
|
|
8894
9891
|
" - Cite the specific unmet-need row and the originating job",
|
|
@@ -8905,6 +9902,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
8905
9902
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
8906
9903
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
8907
9904
|
"",
|
|
9905
|
+
...renderIssueTypeAssignmentStep(),
|
|
9906
|
+
"",
|
|
8908
9907
|
"9. **Create `people:research` issues** for notable competitor",
|
|
8909
9908
|
" leadership or customer-advocacy figures surfaced in the analysis.",
|
|
8910
9909
|
" Keep this list small \u2014 at most three individuals per competitors",
|
|
@@ -8916,6 +9915,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
8916
9915
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
8917
9916
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
8918
9917
|
"",
|
|
9918
|
+
...renderIssueTypeAssignmentStep(),
|
|
9919
|
+
"",
|
|
8919
9920
|
"10. **Commit and push** the competitor-analysis page and the",
|
|
8920
9921
|
" updated archetype page. Close the competitors issue.",
|
|
8921
9922
|
"",
|
|
@@ -9102,6 +10103,8 @@ function buildDiscoverCustomersSkill(paths, issueDefaults) {
|
|
|
9102
10103
|
"1. Create a `customer:discover` issue with `type:customer-profile`,",
|
|
9103
10104
|
` \`priority:${labelsForPhase(issueDefaults, "customer:discover").priority}\`, and \`status:${labelsForPhase(issueDefaults, "customer:discover").status}\`. The body must include the`,
|
|
9104
10105
|
" scope slug and any known archetypes to include or exclude.",
|
|
10106
|
+
"",
|
|
10107
|
+
...renderIssueTypeAssignmentStep(),
|
|
9105
10108
|
"2. Execute Phase 1 (Discover) of the customer-profile-analyst agent.",
|
|
9106
10109
|
"3. Phase 1 writes the discovery report and creates one",
|
|
9107
10110
|
" `customer:profile` issue per prioritized archetype.",
|
|
@@ -9177,6 +10180,8 @@ function buildProfileCustomerSkill(paths, issueDefaults) {
|
|
|
9177
10180
|
"1. Create a `customer:profile` issue with `type:customer-profile`,",
|
|
9178
10181
|
` \`priority:${labelsForPhase(issueDefaults, "customer:profile").priority}\`, and \`status:${labelsForPhase(issueDefaults, "customer:profile").status}\`. The body must include the`,
|
|
9179
10182
|
" archetype slug and (optionally) the segment slug.",
|
|
10183
|
+
"",
|
|
10184
|
+
...renderIssueTypeAssignmentStep(),
|
|
9180
10185
|
"2. Execute Phase 2 (Profile) of the customer-profile-analyst agent.",
|
|
9181
10186
|
" The agent runs 4\u20138 targeted web searches and populates the",
|
|
9182
10187
|
" archetype page.",
|
|
@@ -9253,6 +10258,8 @@ function buildAnalyzeCustomerCompetitorsSkill(paths, issueDefaults) {
|
|
|
9253
10258
|
` \`status:${labelsForPhase(issueDefaults, "customer:competitors").status}\` (or \`status:blocked\` when still dependent on a`,
|
|
9254
10259
|
" Phase 2 profile issue). Body must include the archetype page",
|
|
9255
10260
|
" path.",
|
|
10261
|
+
"",
|
|
10262
|
+
...renderIssueTypeAssignmentStep(),
|
|
9256
10263
|
"2. Execute Phase 3 (Competitors) of the customer-profile-analyst",
|
|
9257
10264
|
" agent. The agent reads `<MATRIX_FILE>` and runs up to 4\u20138 web",
|
|
9258
10265
|
" searches only to close competitor-coverage gaps the matrix does",
|
|
@@ -10962,10 +11969,7 @@ function buildGithubWorkflowBundle(buildPolicy = DEFAULT_BUILD_POLICY) {
|
|
|
10962
11969
|
" - If unclear, ask the user which type applies",
|
|
10963
11970
|
"2. **Compose the issue title** in the format: `<type>: <short description>`",
|
|
10964
11971
|
"3. **Determine the GitHub issue type** based on the prefix:",
|
|
10965
|
-
|
|
10966
|
-
" - `feat:` \u2192 Feature",
|
|
10967
|
-
" - `fix:` \u2192 Bug",
|
|
10968
|
-
" - `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` \u2192 Task",
|
|
11972
|
+
...renderTitlePrefixTypeBullets(),
|
|
10969
11973
|
"4. **Identify prerequisite issues** \u2014 if the user mentions dependencies or blockers, include a **Dependencies** section in the body with `Depends on: #<issue-number>`",
|
|
10970
11974
|
"5. **Determine labels** \u2014 every issue must be created with the following labels:",
|
|
10971
11975
|
" - **`type:*`** \u2014 derived from the issue title prefix:",
|
|
@@ -11451,6 +12455,7 @@ function buildIndustryDiscoveryAnalystSubAgent(paths, issueDefaults) {
|
|
|
11451
12455
|
" downstream research needs to answer)",
|
|
11452
12456
|
" - Cite the evaluation row that justified advancing the vertical",
|
|
11453
12457
|
" - Reference the plan file path for traceability",
|
|
12458
|
+
...renderIssueTypeAssignmentStep({ indent: " ", bullet: true }),
|
|
11454
12459
|
"",
|
|
11455
12460
|
"5. **Cross-link** \u2014 update the plan file's `## Cleared Verticals`",
|
|
11456
12461
|
" table so each row references its newly-created `research:scope`",
|
|
@@ -11541,6 +12546,8 @@ function buildDiscoverIndustriesSkill(paths, issueDefaults) {
|
|
|
11541
12546
|
"1. Create an `industry:discover` issue with `type:industry-discovery`,",
|
|
11542
12547
|
` \`priority:${labelsForPhase(issueDefaults, "industry:discover").priority}\`, and \`status:${labelsForPhase(issueDefaults, "industry:discover").status}\`. Body must include the`,
|
|
11543
12548
|
" verbatim scope, authorized sources, and any overrides.",
|
|
12549
|
+
"",
|
|
12550
|
+
...renderIssueTypeAssignmentStep(),
|
|
11544
12551
|
"2. Execute Phase 1 (Discover) of the industry-discovery-analyst",
|
|
11545
12552
|
" agent.",
|
|
11546
12553
|
"3. Phase 1 creates an `industry:evaluate` issue, which Phase 2 follows",
|
|
@@ -11819,6 +12826,8 @@ function buildMaintenanceAuditSubAgent(paths, tier) {
|
|
|
11819
12826
|
"4. Commit, push, open a PR (if applicable), and close the issue per",
|
|
11820
12827
|
" your project's PR workflow.",
|
|
11821
12828
|
"",
|
|
12829
|
+
...renderIssueTypeAssignmentBlanket(),
|
|
12830
|
+
"",
|
|
11822
12831
|
"---",
|
|
11823
12832
|
"",
|
|
11824
12833
|
...renderClaimVerificationSection(),
|
|
@@ -12251,6 +13260,8 @@ function buildMaintenanceAuditSkill(paths, issueDefaults) {
|
|
|
12251
13260
|
" - `<AUDIT_ROOT>` \u2014 where to write the audit report",
|
|
12252
13261
|
" - `<AUDIT_SLUG>` \u2014 short identifier for this audit",
|
|
12253
13262
|
" - The audit checks to run (defaults to the full check catalog)",
|
|
13263
|
+
"",
|
|
13264
|
+
...renderIssueTypeAssignmentStep(),
|
|
12254
13265
|
"2. Execute Phase 1 (Scan) of the maintenance-audit agent.",
|
|
12255
13266
|
"3. If auto-fixable findings exist, a `maint:fix` issue is created",
|
|
12256
13267
|
" automatically.",
|
|
@@ -12315,6 +13326,8 @@ function buildMaintenanceVerifySkill(issueDefaults) {
|
|
|
12315
13326
|
" - The Phase 2 fix report path (if one exists)",
|
|
12316
13327
|
" - The `Paths Touched` list (copied from the fix report)",
|
|
12317
13328
|
" - The audit check catalog (copied from the scan issue)",
|
|
13329
|
+
"",
|
|
13330
|
+
...renderIssueTypeAssignmentStep(),
|
|
12318
13331
|
"2. Execute Phase 3 (Verify) of the maintenance-audit agent.",
|
|
12319
13332
|
"",
|
|
12320
13333
|
"## Output",
|
|
@@ -12824,6 +13837,8 @@ function buildMeetingAnalystSubAgent(tier) {
|
|
|
12824
13837
|
" - Always create a `meeting:link` issue \u2014 blocked on the draft issue if one",
|
|
12825
13838
|
" was created, otherwise blocked on the notes issue",
|
|
12826
13839
|
"",
|
|
13840
|
+
...renderIssueTypeAssignmentStep(),
|
|
13841
|
+
"",
|
|
12827
13842
|
"7. **Commit the extraction content first.** Stage and commit",
|
|
12828
13843
|
" the `insights/{type}/<basename>.md` file (and any newly",
|
|
12829
13844
|
" created `insights/index.md` / `insights/{type}/index.md`",
|
|
@@ -13023,6 +14038,8 @@ function buildMeetingAnalystSubAgent(tier) {
|
|
|
13023
14038
|
"",
|
|
13024
14039
|
"### Steps",
|
|
13025
14040
|
"",
|
|
14041
|
+
...renderIssueTypeAssignmentBlanket(),
|
|
14042
|
+
"",
|
|
13026
14043
|
"1. Read the drafts from Phase 3 (if they exist) and the extraction",
|
|
13027
14044
|
" from Phase 1 at `<meetingsRoot>/insights/{type}/<basename>.md`.",
|
|
13028
14045
|
" Re-read the extraction frontmatter for `meeting_kind` and `areas`,",
|
|
@@ -13086,700 +14103,221 @@ function buildMeetingAnalystSubAgent(tier) {
|
|
|
13086
14103
|
" `## Downstream Artifacts` section listing every issue and",
|
|
13087
14104
|
" document created from this meeting. Note any items that were",
|
|
13088
14105
|
" deferred to follow-up issues because of the area gate.",
|
|
13089
|
-
"8. **Update the meeting notes** at",
|
|
13090
|
-
" `<meetingsRoot>/notes/{type}/<basename>.md` with a",
|
|
13091
|
-
" `## Related Issues` section listing all issues created from this",
|
|
13092
|
-
" meeting.",
|
|
13093
|
-
"9. Comment on the parent extract issue with a summary linking to all",
|
|
13094
|
-
" created artifacts.",
|
|
13095
|
-
"10. Commit and push (if any file changes were made), then close the link issue.",
|
|
13096
|
-
"",
|
|
13097
|
-
"---",
|
|
13098
|
-
"",
|
|
13099
|
-
"## GitHub Integration",
|
|
13100
|
-
"",
|
|
13101
|
-
"- Use `gh` CLI for all GitHub operations",
|
|
13102
|
-
"- Apply the appropriate `meeting:*` phase label to each phase issue",
|
|
13103
|
-
"- Use `type:docs` for documentation-producing issues, `type:chore` for",
|
|
13104
|
-
" maintenance/organizational tasks the pipeline can action",
|
|
13105
|
-
"- Do **not** file issues for human-owned action items \u2014 per the",
|
|
13106
|
-
" **Action-item filing policy** they live only in the notes",
|
|
13107
|
-
" `## Action Items` table",
|
|
13108
|
-
"- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)",
|
|
13109
|
-
"- Reference the source meeting transcript in all created issues",
|
|
13110
|
-
"- Link phase issues with `Depends on: #N` to enforce ordering",
|
|
13111
|
-
"",
|
|
13112
|
-
"## When to Shorten the Pipeline",
|
|
13113
|
-
"",
|
|
13114
|
-
"- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session",
|
|
13115
|
-
"- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue",
|
|
13116
|
-
"- **Only action items**: extract + notes + link (3 phase issues)"
|
|
13117
|
-
].join("\n")
|
|
13118
|
-
};
|
|
13119
|
-
}
|
|
13120
|
-
var processMeetingSkill = {
|
|
13121
|
-
name: "process-meeting",
|
|
13122
|
-
description: "Process a meeting transcript through the 4-phase meeting analysis pipeline",
|
|
13123
|
-
disableModelInvocation: true,
|
|
13124
|
-
userInvocable: true,
|
|
13125
|
-
context: "fork",
|
|
13126
|
-
agent: "meeting-analyst",
|
|
13127
|
-
platforms: { cursor: { exclude: true } },
|
|
13128
|
-
instructions: [
|
|
13129
|
-
"# Process Meeting",
|
|
13130
|
-
"",
|
|
13131
|
-
"Kick off meeting processing by executing Phase 1 (Extract) and",
|
|
13132
|
-
"creating downstream phase issues for the remaining phases. Inputs",
|
|
13133
|
-
"live in the **sibling-tree layout**: pass any file from",
|
|
13134
|
-
"`<meetingsRoot>/notes/{type}/` or `<meetingsRoot>/transcripts/{type}/`",
|
|
13135
|
-
"(both, notes-only, and transcript-only are all valid input cases).",
|
|
13136
|
-
"",
|
|
13137
|
-
"## Usage",
|
|
13138
|
-
"",
|
|
13139
|
-
"/process-meeting <path-to-notes-or-transcript>",
|
|
13140
|
-
"",
|
|
13141
|
-
"## Basename-pairing algorithm",
|
|
13142
|
-
"",
|
|
13143
|
-
"The user may pass either a notes-tree path or a transcripts-tree",
|
|
13144
|
-
"path. Resolve the sibling implicitly via filesystem lookup \u2014",
|
|
13145
|
-
"do **not** prompt the user or fail-loud when the sibling is",
|
|
13146
|
-
"absent:",
|
|
13147
|
-
"",
|
|
13148
|
-
"1. Infer the **basename** (filename without the `.md` extension)",
|
|
13149
|
-
" and the `{internal,external}` partition from the provided path.",
|
|
13150
|
-
" Both segments are usually adjacent in the path \u2014",
|
|
13151
|
-
" `\u2026/notes/internal/2026-03-14-sprint-kickoff.md` yields basename",
|
|
13152
|
-
" `2026-03-14-sprint-kickoff` and type `internal`.",
|
|
13153
|
-
"2. Determine the **input tree** from the path:",
|
|
13154
|
-
" - If the path contains `/notes/`, treat it as the notes input",
|
|
13155
|
-
" and look for the sibling at",
|
|
13156
|
-
" `<meetingsRoot>/transcripts/<type>/<basename>.md`.",
|
|
13157
|
-
" - If the path contains `/transcripts/`, treat it as the",
|
|
13158
|
-
" transcript input and look for the sibling at",
|
|
13159
|
-
" `<meetingsRoot>/notes/<type>/<basename>.md`.",
|
|
13160
|
-
" - If the path matches neither (e.g. an ad-hoc location), infer",
|
|
13161
|
-
" basename + type as best you can from the filename and",
|
|
13162
|
-
" surrounding folder segments, then proceed with whichever",
|
|
13163
|
-
" sibling-tree lookups succeed. Best-effort, never fail-loud.",
|
|
13164
|
-
"3. Read **every** sibling that exists on disk. The combination",
|
|
13165
|
-
" (notes present, transcript present, both present) selects the",
|
|
13166
|
-
" Phase-1 input case from the **input-case matrix** in the",
|
|
13167
|
-
" `meeting-analyst` agent prompt.",
|
|
13168
|
-
"4. A missing sibling is a normal outcome \u2014 proceed with whatever",
|
|
13169
|
-
" was found. Notes-only and transcript-only are both valid",
|
|
13170
|
-
" Phase-1 input cases; the agent never warns or prompts the",
|
|
13171
|
-
" user about the absence.",
|
|
13172
|
-
"",
|
|
13173
|
-
"## Steps",
|
|
13174
|
-
"",
|
|
13175
|
-
"1. Resolve the basename, partition, and any sibling files using",
|
|
13176
|
-
" the **Basename-pairing algorithm** above",
|
|
13177
|
-
"2. Execute Phase 1 (Extract) \u2014 categorize the available content into",
|
|
13178
|
-
" decisions, requirements, action items, open questions, and more.",
|
|
13179
|
-
" Tag each action item's disposition (`agent-workable` vs",
|
|
13180
|
-
" `human-owned`) per the agent's **Action-item filing policy** so",
|
|
13181
|
-
" Phase 4 keeps human-owned tasks out of the issue queue",
|
|
13182
|
-
"3. Write the extraction to",
|
|
13183
|
-
" `<meetingsRoot>/insights/{type}/<basename>.md`",
|
|
13184
|
-
"4. Create downstream phase issues using `gh issue create`:",
|
|
13185
|
-
" - `meeting:notes` issue (always)",
|
|
13186
|
-
" - `meeting:draft` issue (if requirements or decisions were found)",
|
|
13187
|
-
" - `meeting:link` issue (always)",
|
|
13188
|
-
"5. Each downstream issue includes `Depends on:` linking to its predecessor",
|
|
13189
|
-
"6. Commit and push the extraction file",
|
|
13190
|
-
"",
|
|
13191
|
-
"## Input",
|
|
13192
|
-
"",
|
|
13193
|
-
"Provide a path to a file in either `notes/` or `transcripts/`. The",
|
|
13194
|
-
"agent will look up the sibling automatically via basename match. A",
|
|
13195
|
-
"missing sibling is a normal case (notes-only or transcript-only) \u2014",
|
|
13196
|
-
"the agent handles all three input cases.",
|
|
13197
|
-
"",
|
|
13198
|
-
"## Output",
|
|
13199
|
-
"",
|
|
13200
|
-
"- A structured extraction at",
|
|
13201
|
-
" `<meetingsRoot>/insights/{type}/<basename>.md`",
|
|
13202
|
-
"- Phase issues with `meeting:*` labels for downstream agent sessions",
|
|
13203
|
-
" to pick up (notes, draft, link)"
|
|
13204
|
-
].join("\n")
|
|
13205
|
-
};
|
|
13206
|
-
function buildMeetingAnalysisBundle(tier = AGENT_MODEL.BALANCED) {
|
|
13207
|
-
return {
|
|
13208
|
-
name: "meeting-analysis",
|
|
13209
|
-
description: "Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)",
|
|
13210
|
-
appliesWhen: () => true,
|
|
13211
|
-
rules: [
|
|
13212
|
-
{
|
|
13213
|
-
name: "meeting-processing-workflow",
|
|
13214
|
-
description: "Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions",
|
|
13215
|
-
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
13216
|
-
content: [
|
|
13217
|
-
"# Meeting Processing Workflow",
|
|
13218
|
-
"",
|
|
13219
|
-
"Use `/process-meeting <path>` to process a meeting through a",
|
|
13220
|
-
"4-phase pipeline (extract \u2192 notes \u2192 draft \u2192 link). Each phase runs as a",
|
|
13221
|
-
"separate agent session tracked by a GitHub issue with a `meeting:*` label.",
|
|
13222
|
-
"See the `meeting-analyst` agent definition for full workflow details.",
|
|
13223
|
-
"",
|
|
13224
|
-
"Meeting artifacts live in **three parallel trees** rooted at the",
|
|
13225
|
-
"project's meetings root:",
|
|
13226
|
-
"",
|
|
13227
|
-
"- `transcripts/{internal,external}/` \u2014 verbatim transcripts (evidence)",
|
|
13228
|
-
"- `notes/{internal,external}/` \u2014 curated narrative summary",
|
|
13229
|
-
" (input + Phase 2 output)",
|
|
13230
|
-
"- `insights/{internal,external}/` \u2014 structured extraction (Phase 1 output)",
|
|
13231
|
-
"",
|
|
13232
|
-
"The three trees share identical basenames so a meeting's siblings",
|
|
13233
|
-
"are looked up by filename, not by frontmatter cross-references.",
|
|
13234
|
-
"Phase 1 accepts every input case (notes + transcript, notes only,",
|
|
13235
|
-
"or transcript only) and Phase 2 enhances the notes file in place",
|
|
13236
|
-
"rather than authoring it from scratch.",
|
|
13237
|
-
"",
|
|
13238
|
-
"Notes and insights files may carry optional frontmatter fields",
|
|
13239
|
-
"`slug`, `source`, `transcript_available`, and `confidence`",
|
|
13240
|
-
"alongside the existing `meeting_type` and `areas` fields. Missing",
|
|
13241
|
-
"frontmatter is treated as a normal input case \u2014 never fail-loud.",
|
|
13242
|
-
"",
|
|
13243
|
-
"Meeting notes may declare a `meeting_type` (one of the project's",
|
|
13244
|
-
"recognized types) and an `areas: [...]` list. The `meeting_type`",
|
|
13245
|
-
"resolves to a generic kind \u2014 `planning` / `review` / `brainstorm` /",
|
|
13246
|
-
"`standup` / `external` / `other` \u2014 that drives type-specific",
|
|
13247
|
-
"extraction rules in phases 1\u20132. The `areas` list scopes phase-4",
|
|
13248
|
-
"direct edits to the doc-root sub-folders declared in the project's",
|
|
13249
|
-
"**Area \u2192 doc-root mapping** table. When both fields are absent",
|
|
13250
|
-
"the pipeline falls back to the default workflow (kind `other`,",
|
|
13251
|
-
"no area gating).",
|
|
13252
|
-
"",
|
|
13253
|
-
"Phase 4 applies an **agent-workability split** to action items:",
|
|
13254
|
-
"items that yield a documentation deliverable an agent can author",
|
|
13255
|
-
"are filed through their dedicated downstream channel",
|
|
13256
|
-
"(`req:write`, `docs:write`, `bcm:*`, `research:scope`, roadmap",
|
|
13257
|
-
"follow-up); human-owned tasks (send / schedule / install /",
|
|
13258
|
-
"decide / communicate / get-access / build-elsewhere) are",
|
|
13259
|
-
"recorded **only** in the notes `## Action Items` table, which is",
|
|
13260
|
-
"the **system of record for human follow-ups** \u2014 no GitHub issue",
|
|
13261
|
-
"is filed for them. Consumers tune or disable the split via",
|
|
13262
|
-
"`AgentConfigOptions.meetings.actionItemFiling`."
|
|
13263
|
-
].join("\n"),
|
|
13264
|
-
platforms: {
|
|
13265
|
-
cursor: { exclude: true }
|
|
13266
|
-
},
|
|
13267
|
-
tags: ["workflow"]
|
|
13268
|
-
}
|
|
13269
|
-
],
|
|
13270
|
-
skills: [processMeetingSkill],
|
|
13271
|
-
subAgents: [buildMeetingAnalystSubAgent(tier)],
|
|
13272
|
-
labels: [
|
|
13273
|
-
{
|
|
13274
|
-
name: "type:meeting-processing",
|
|
13275
|
-
color: "5319E7",
|
|
13276
|
-
description: "Meeting transcript processing pipeline"
|
|
13277
|
-
},
|
|
13278
|
-
{
|
|
13279
|
-
name: "meeting:extract",
|
|
13280
|
-
color: "C5DEF5",
|
|
13281
|
-
description: "Phase 1: raw extraction from a meeting transcript"
|
|
13282
|
-
},
|
|
13283
|
-
{
|
|
13284
|
-
name: "meeting:notes",
|
|
13285
|
-
color: "BFDADC",
|
|
13286
|
-
description: "Phase 2: curated notes derived from an extraction"
|
|
13287
|
-
},
|
|
13288
|
-
{
|
|
13289
|
-
name: "meeting:draft",
|
|
13290
|
-
color: "D4C5F9",
|
|
13291
|
-
description: "Phase 3: draft follow-up issues proposed from notes"
|
|
13292
|
-
},
|
|
13293
|
-
{
|
|
13294
|
-
name: "meeting:link",
|
|
13295
|
-
color: "FEF2C0",
|
|
13296
|
-
description: "Phase 4: linking/reconciling drafted issues with existing work"
|
|
13297
|
-
}
|
|
13298
|
-
]
|
|
13299
|
-
};
|
|
13300
|
-
}
|
|
13301
|
-
var meetingAnalysisBundle = buildMeetingAnalysisBundle();
|
|
13302
|
-
|
|
13303
|
-
// src/agent/bundles/bundle-ownership.ts
|
|
13304
|
-
var BUNDLE_OWNERSHIP = {
|
|
13305
|
-
agenda: {
|
|
13306
|
-
typeLabels: ["agenda"],
|
|
13307
|
-
phaseLabelPrefixes: ["agenda:"],
|
|
13308
|
-
scheduledTaskIds: ["worker-agenda"],
|
|
13309
|
-
emitsDocs: true,
|
|
13310
|
-
downstreamIssueKinds: true
|
|
13311
|
-
},
|
|
13312
|
-
"bcm-writer": {
|
|
13313
|
-
typeLabels: ["bcm-document"],
|
|
13314
|
-
phaseLabelPrefixes: ["bcm:"],
|
|
13315
|
-
scheduledTaskIds: ["worker-bcm-writer"],
|
|
13316
|
-
emitsDocs: true,
|
|
13317
|
-
downstreamIssueKinds: true
|
|
13318
|
-
},
|
|
13319
|
-
"business-models": {
|
|
13320
|
-
typeLabels: ["business-model"],
|
|
13321
|
-
phaseLabelPrefixes: ["business-models:"],
|
|
13322
|
-
scheduledTaskIds: ["worker-business-models"],
|
|
13323
|
-
emitsDocs: true,
|
|
13324
|
-
downstreamIssueKinds: true
|
|
13325
|
-
},
|
|
13326
|
-
"company-profile": {
|
|
13327
|
-
typeLabels: ["company-profile"],
|
|
13328
|
-
phaseLabelPrefixes: ["company:"],
|
|
13329
|
-
scheduledTaskIds: ["worker-company-profile"],
|
|
13330
|
-
emitsDocs: true,
|
|
13331
|
-
downstreamIssueKinds: true
|
|
13332
|
-
},
|
|
13333
|
-
"customer-profile": {
|
|
13334
|
-
typeLabels: ["customer-profile"],
|
|
13335
|
-
phaseLabelPrefixes: ["customer:"],
|
|
13336
|
-
scheduledTaskIds: ["worker-customer-profile"],
|
|
13337
|
-
emitsDocs: true,
|
|
13338
|
-
downstreamIssueKinds: true
|
|
13339
|
-
},
|
|
13340
|
-
"docs-sync": {
|
|
13341
|
-
typeLabels: ["docs-sync"],
|
|
13342
|
-
phaseLabelPrefixes: ["docs-sync:"],
|
|
13343
|
-
scheduledTaskIds: ["worker-docs-sync"],
|
|
13344
|
-
emitsDocs: true,
|
|
13345
|
-
downstreamIssueKinds: true
|
|
13346
|
-
},
|
|
13347
|
-
"industry-discovery": {
|
|
13348
|
-
typeLabels: ["industry-discovery"],
|
|
13349
|
-
phaseLabelPrefixes: ["industry:"],
|
|
13350
|
-
scheduledTaskIds: ["worker-industry-discovery"],
|
|
13351
|
-
emitsDocs: true,
|
|
13352
|
-
downstreamIssueKinds: true
|
|
13353
|
-
},
|
|
13354
|
-
"maintenance-audit": {
|
|
13355
|
-
typeLabels: ["maintenance"],
|
|
13356
|
-
phaseLabelPrefixes: ["maint:"],
|
|
13357
|
-
scheduledTaskIds: ["worker-maintenance"],
|
|
13358
|
-
emitsDocs: false,
|
|
13359
|
-
downstreamIssueKinds: true
|
|
13360
|
-
},
|
|
13361
|
-
"meeting-analysis": {
|
|
13362
|
-
typeLabels: ["meeting-processing"],
|
|
13363
|
-
phaseLabelPrefixes: ["meeting:"],
|
|
13364
|
-
scheduledTaskIds: ["worker-meeting-analysis"],
|
|
13365
|
-
emitsDocs: true,
|
|
13366
|
-
downstreamIssueKinds: true
|
|
13367
|
-
},
|
|
13368
|
-
orchestrator: {
|
|
13369
|
-
// The orchestrator pipeline manager itself ships with the
|
|
13370
|
-
// `worker-orchestrator` scheduled task. It owns no `type:*` label
|
|
13371
|
-
// (it dispatches every type) and no phase-label prefix.
|
|
13372
|
-
typeLabels: [],
|
|
13373
|
-
phaseLabelPrefixes: [],
|
|
13374
|
-
scheduledTaskIds: ["worker-orchestrator"],
|
|
13375
|
-
emitsDocs: false,
|
|
13376
|
-
downstreamIssueKinds: false
|
|
13377
|
-
},
|
|
13378
|
-
"people-profile": {
|
|
13379
|
-
typeLabels: ["people-profile"],
|
|
13380
|
-
phaseLabelPrefixes: ["people:"],
|
|
13381
|
-
scheduledTaskIds: ["worker-people-profile"],
|
|
13382
|
-
emitsDocs: true,
|
|
13383
|
-
downstreamIssueKinds: true
|
|
13384
|
-
},
|
|
13385
|
-
"pr-review": {
|
|
13386
|
-
typeLabels: ["pr-review"],
|
|
13387
|
-
phaseLabelPrefixes: [],
|
|
13388
|
-
scheduledTaskIds: ["worker-pr-review"],
|
|
13389
|
-
emitsDocs: false,
|
|
13390
|
-
downstreamIssueKinds: false
|
|
13391
|
-
},
|
|
13392
|
-
"regulatory-research": {
|
|
13393
|
-
typeLabels: ["regulatory-research"],
|
|
13394
|
-
phaseLabelPrefixes: ["regulatory:"],
|
|
13395
|
-
scheduledTaskIds: ["worker-regulatory-research"],
|
|
13396
|
-
emitsDocs: true,
|
|
13397
|
-
downstreamIssueKinds: true
|
|
13398
|
-
},
|
|
13399
|
-
"requirements-analyst": {
|
|
13400
|
-
typeLabels: ["requirement"],
|
|
13401
|
-
phaseLabelPrefixes: ["req:"],
|
|
13402
|
-
scheduledTaskIds: ["worker-requirements-analyst"],
|
|
13403
|
-
emitsDocs: true,
|
|
13404
|
-
downstreamIssueKinds: true
|
|
13405
|
-
},
|
|
13406
|
-
"requirements-reviewer": {
|
|
13407
|
-
// Co-owns `type:requirement` with the analyst and writer; owns
|
|
13408
|
-
// the `req:review` and `req:deprecate` phase labels exactly.
|
|
13409
|
-
typeLabels: ["requirement"],
|
|
13410
|
-
phaseLabelPrefixes: ["req:review", "req:deprecate"],
|
|
13411
|
-
scheduledTaskIds: ["worker-requirements-reviewer"],
|
|
13412
|
-
emitsDocs: true,
|
|
13413
|
-
downstreamIssueKinds: true
|
|
13414
|
-
},
|
|
13415
|
-
"requirements-writer": {
|
|
13416
|
-
// Co-owns `type:requirement` with the analyst and reviewer; owns
|
|
13417
|
-
// the `req:write` phase label exactly.
|
|
13418
|
-
typeLabels: ["requirement"],
|
|
13419
|
-
phaseLabelPrefixes: ["req:write"],
|
|
13420
|
-
scheduledTaskIds: ["worker-requirements-writer"],
|
|
13421
|
-
emitsDocs: true,
|
|
13422
|
-
downstreamIssueKinds: true
|
|
13423
|
-
},
|
|
13424
|
-
"research-pipeline": {
|
|
13425
|
-
typeLabels: ["research"],
|
|
13426
|
-
phaseLabelPrefixes: ["research:"],
|
|
13427
|
-
scheduledTaskIds: ["worker-research"],
|
|
13428
|
-
emitsDocs: true,
|
|
13429
|
-
downstreamIssueKinds: true
|
|
13430
|
-
},
|
|
13431
|
-
"software-profile": {
|
|
13432
|
-
typeLabels: ["software-profile"],
|
|
13433
|
-
phaseLabelPrefixes: ["software:"],
|
|
13434
|
-
scheduledTaskIds: ["worker-software-profile"],
|
|
13435
|
-
emitsDocs: true,
|
|
13436
|
-
downstreamIssueKinds: true
|
|
13437
|
-
},
|
|
13438
|
-
"standards-research": {
|
|
13439
|
-
typeLabels: ["standards-research"],
|
|
13440
|
-
phaseLabelPrefixes: ["standards:"],
|
|
13441
|
-
scheduledTaskIds: ["worker-standards-research"],
|
|
13442
|
-
emitsDocs: true,
|
|
13443
|
-
downstreamIssueKinds: true
|
|
13444
|
-
}
|
|
13445
|
-
};
|
|
13446
|
-
var CONVENTIONAL_COMMIT_TYPE_LABELS = [
|
|
13447
|
-
"type:chore",
|
|
13448
|
-
"type:docs",
|
|
13449
|
-
"type:feat",
|
|
13450
|
-
"type:fix",
|
|
13451
|
-
"type:hotfix",
|
|
13452
|
-
"type:refactor",
|
|
13453
|
-
"type:release"
|
|
13454
|
-
];
|
|
13455
|
-
var PHASE_LABEL_TYPE_MAP = buildPhaseLabelTypeMap();
|
|
13456
|
-
function typeLabelForPhaseLabel(phaseLabel) {
|
|
13457
|
-
const exact = PHASE_LABEL_TYPE_MAP[phaseLabel];
|
|
13458
|
-
if (exact !== void 0 && !phaseLabel.endsWith(":")) {
|
|
13459
|
-
return exact;
|
|
13460
|
-
}
|
|
13461
|
-
let bestMatcher;
|
|
13462
|
-
for (const matcher of Object.keys(PHASE_LABEL_TYPE_MAP)) {
|
|
13463
|
-
if (!matcher.endsWith(":")) {
|
|
13464
|
-
continue;
|
|
13465
|
-
}
|
|
13466
|
-
if (!phaseLabel.startsWith(matcher)) {
|
|
13467
|
-
continue;
|
|
13468
|
-
}
|
|
13469
|
-
if (bestMatcher === void 0 || matcher.length > bestMatcher.length) {
|
|
13470
|
-
bestMatcher = matcher;
|
|
13471
|
-
}
|
|
13472
|
-
}
|
|
13473
|
-
return bestMatcher === void 0 ? void 0 : PHASE_LABEL_TYPE_MAP[bestMatcher];
|
|
13474
|
-
}
|
|
13475
|
-
function resolveTypeLabelForLabels(labels) {
|
|
13476
|
-
const phaseLabels = [];
|
|
13477
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
13478
|
-
for (const label of labels) {
|
|
13479
|
-
const typeLabel = typeLabelForPhaseLabel(label);
|
|
13480
|
-
if (typeLabel === void 0) {
|
|
13481
|
-
continue;
|
|
13482
|
-
}
|
|
13483
|
-
phaseLabels.push(label);
|
|
13484
|
-
candidates.add(typeLabel);
|
|
13485
|
-
}
|
|
13486
|
-
const candidateTypeLabels = Array.from(candidates).sort();
|
|
13487
|
-
if (candidateTypeLabels.length === 0) {
|
|
13488
|
-
return { outcome: "none", candidateTypeLabels: [], phaseLabels: [] };
|
|
13489
|
-
}
|
|
13490
|
-
if (candidateTypeLabels.length === 1) {
|
|
13491
|
-
return {
|
|
13492
|
-
outcome: "match",
|
|
13493
|
-
typeLabel: candidateTypeLabels[0],
|
|
13494
|
-
candidateTypeLabels,
|
|
13495
|
-
phaseLabels
|
|
13496
|
-
};
|
|
13497
|
-
}
|
|
13498
|
-
return { outcome: "ambiguous", candidateTypeLabels, phaseLabels };
|
|
14106
|
+
"8. **Update the meeting notes** at",
|
|
14107
|
+
" `<meetingsRoot>/notes/{type}/<basename>.md` with a",
|
|
14108
|
+
" `## Related Issues` section listing all issues created from this",
|
|
14109
|
+
" meeting.",
|
|
14110
|
+
"9. Comment on the parent extract issue with a summary linking to all",
|
|
14111
|
+
" created artifacts.",
|
|
14112
|
+
"10. Commit and push (if any file changes were made), then close the link issue.",
|
|
14113
|
+
"",
|
|
14114
|
+
"---",
|
|
14115
|
+
"",
|
|
14116
|
+
"## GitHub Integration",
|
|
14117
|
+
"",
|
|
14118
|
+
"- Use `gh` CLI for all GitHub operations",
|
|
14119
|
+
"- Apply the appropriate `meeting:*` phase label to each phase issue",
|
|
14120
|
+
"- Use `type:docs` for documentation-producing issues, `type:chore` for",
|
|
14121
|
+
" maintenance/organizational tasks the pipeline can action",
|
|
14122
|
+
"- Do **not** file issues for human-owned action items \u2014 per the",
|
|
14123
|
+
" **Action-item filing policy** they live only in the notes",
|
|
14124
|
+
" `## Action Items` table",
|
|
14125
|
+
"- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)",
|
|
14126
|
+
"- Reference the source meeting transcript in all created issues",
|
|
14127
|
+
"- Link phase issues with `Depends on: #N` to enforce ordering",
|
|
14128
|
+
"",
|
|
14129
|
+
"## When to Shorten the Pipeline",
|
|
14130
|
+
"",
|
|
14131
|
+
"- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session",
|
|
14132
|
+
"- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue",
|
|
14133
|
+
"- **Only action items**: extract + notes + link (3 phase issues)"
|
|
14134
|
+
].join("\n")
|
|
14135
|
+
};
|
|
13499
14136
|
}
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
}
|
|
13508
|
-
|
|
13509
|
-
"
|
|
13510
|
-
"",
|
|
13511
|
-
"Every phased-pipeline bundle pairs its `<bundle>:<phase>` labels",
|
|
13512
|
-
"with exactly one `type:<bundle>` label. That type label is the",
|
|
13513
|
-
"**dedup + dispatch signal**: agents de-duplicate downstream work",
|
|
13514
|
-
'with `gh issue list --label "type:<bundle>"`, and Phase E derives',
|
|
13515
|
-
"its funnel-tier sort key from the issue's `type:*` label. An issue",
|
|
13516
|
-
"that carries the phase label but a conventional-commit `type:*`",
|
|
13517
|
-
"(`type:feat`, `type:docs`, \u2026, stamped from its title prefix by the",
|
|
13518
|
-
"generic create-issue workflow) is invisible to that dedup query and",
|
|
13519
|
-
"mis-tiers in dispatch.",
|
|
13520
|
-
"",
|
|
13521
|
-
"The pairing below is derived from the canonical bundle-ownership",
|
|
13522
|
-
"map \u2014 the same source of truth that generates the label registry.",
|
|
13523
|
-
"Matchers ending in `*` match by prefix; the rest match exactly, and",
|
|
13524
|
-
"an exact match always beats a prefix match.",
|
|
14137
|
+
var processMeetingSkill = {
|
|
14138
|
+
name: "process-meeting",
|
|
14139
|
+
description: "Process a meeting transcript through the 4-phase meeting analysis pipeline",
|
|
14140
|
+
disableModelInvocation: true,
|
|
14141
|
+
userInvocable: true,
|
|
14142
|
+
context: "fork",
|
|
14143
|
+
agent: "meeting-analyst",
|
|
14144
|
+
platforms: { cursor: { exclude: true } },
|
|
14145
|
+
instructions: [
|
|
14146
|
+
"# Process Meeting",
|
|
13525
14147
|
"",
|
|
13526
|
-
"
|
|
13527
|
-
"
|
|
13528
|
-
|
|
14148
|
+
"Kick off meeting processing by executing Phase 1 (Extract) and",
|
|
14149
|
+
"creating downstream phase issues for the remaining phases. Inputs",
|
|
14150
|
+
"live in the **sibling-tree layout**: pass any file from",
|
|
14151
|
+
"`<meetingsRoot>/notes/{type}/` or `<meetingsRoot>/transcripts/{type}/`",
|
|
14152
|
+
"(both, notes-only, and transcript-only are all valid input cases).",
|
|
13529
14153
|
"",
|
|
13530
|
-
"
|
|
14154
|
+
"## Usage",
|
|
13531
14155
|
"",
|
|
13532
|
-
"
|
|
13533
|
-
"mode and emits one summary line:",
|
|
14156
|
+
"/process-meeting <path-to-notes-or-transcript>",
|
|
13534
14157
|
"",
|
|
13535
|
-
"
|
|
13536
|
-
"LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>",
|
|
13537
|
-
"```",
|
|
14158
|
+
"## Basename-pairing algorithm",
|
|
13538
14159
|
"",
|
|
13539
|
-
"
|
|
13540
|
-
"
|
|
14160
|
+
"The user may pass either a notes-tree path or a transcripts-tree",
|
|
14161
|
+
"path. Resolve the sibling implicitly via filesystem lookup \u2014",
|
|
14162
|
+
"do **not** prompt the user or fail-loud when the sibling is",
|
|
14163
|
+
"absent:",
|
|
13541
14164
|
"",
|
|
13542
|
-
"
|
|
13543
|
-
"
|
|
13544
|
-
"
|
|
13545
|
-
"
|
|
14165
|
+
"1. Infer the **basename** (filename without the `.md` extension)",
|
|
14166
|
+
" and the `{internal,external}` partition from the provided path.",
|
|
14167
|
+
" Both segments are usually adjacent in the path \u2014",
|
|
14168
|
+
" `\u2026/notes/internal/2026-03-14-sprint-kickoff.md` yields basename",
|
|
14169
|
+
" `2026-03-14-sprint-kickoff` and type `internal`.",
|
|
14170
|
+
"2. Determine the **input tree** from the path:",
|
|
14171
|
+
" - If the path contains `/notes/`, treat it as the notes input",
|
|
14172
|
+
" and look for the sibling at",
|
|
14173
|
+
" `<meetingsRoot>/transcripts/<type>/<basename>.md`.",
|
|
14174
|
+
" - If the path contains `/transcripts/`, treat it as the",
|
|
14175
|
+
" transcript input and look for the sibling at",
|
|
14176
|
+
" `<meetingsRoot>/notes/<type>/<basename>.md`.",
|
|
14177
|
+
" - If the path matches neither (e.g. an ad-hoc location), infer",
|
|
14178
|
+
" basename + type as best you can from the filename and",
|
|
14179
|
+
" surrounding folder segments, then proceed with whichever",
|
|
14180
|
+
" sibling-tree lookups succeed. Best-effort, never fail-loud.",
|
|
14181
|
+
"3. Read **every** sibling that exists on disk. The combination",
|
|
14182
|
+
" (notes present, transcript present, both present) selects the",
|
|
14183
|
+
" Phase-1 input case from the **input-case matrix** in the",
|
|
14184
|
+
" `meeting-analyst` agent prompt.",
|
|
14185
|
+
"4. A missing sibling is a normal outcome \u2014 proceed with whatever",
|
|
14186
|
+
" was found. Notes-only and transcript-only are both valid",
|
|
14187
|
+
" Phase-1 input cases; the agent never warns or prompts the",
|
|
14188
|
+
" user about the absence.",
|
|
13546
14189
|
"",
|
|
13547
|
-
"
|
|
14190
|
+
"## Steps",
|
|
13548
14191
|
"",
|
|
13549
|
-
"
|
|
13550
|
-
"the
|
|
13551
|
-
"
|
|
13552
|
-
"
|
|
13553
|
-
"
|
|
13554
|
-
"
|
|
13555
|
-
"
|
|
14192
|
+
"1. Resolve the basename, partition, and any sibling files using",
|
|
14193
|
+
" the **Basename-pairing algorithm** above",
|
|
14194
|
+
"2. Execute Phase 1 (Extract) \u2014 categorize the available content into",
|
|
14195
|
+
" decisions, requirements, action items, open questions, and more.",
|
|
14196
|
+
" Tag each action item's disposition (`agent-workable` vs",
|
|
14197
|
+
" `human-owned`) per the agent's **Action-item filing policy** so",
|
|
14198
|
+
" Phase 4 keeps human-owned tasks out of the issue queue",
|
|
14199
|
+
"3. Write the extraction to",
|
|
14200
|
+
" `<meetingsRoot>/insights/{type}/<basename>.md`",
|
|
14201
|
+
"4. Create downstream phase issues using `gh issue create`:",
|
|
14202
|
+
" - `meeting:notes` issue (always)",
|
|
14203
|
+
" - `meeting:draft` issue (if requirements or decisions were found)",
|
|
14204
|
+
" - `meeting:link` issue (always)",
|
|
13556
14205
|
"",
|
|
13557
|
-
|
|
13558
|
-
"
|
|
13559
|
-
"
|
|
13560
|
-
"| No `type:*` label at all | **add** the required label |",
|
|
13561
|
-
"| Only conventional-commit `type:*` label(s) | **replace** \u2014 remove them, add the required label |",
|
|
13562
|
-
"| Required label present **plus** a stray conventional-commit one | **remove** the stray, leaving exactly one |",
|
|
13563
|
-
"| A `type:*` label owned by a **different** bundle | **flag** `status:needs-attention` \u2014 never guessed at |",
|
|
13564
|
-
"| Phase labels imply **two or more** type labels | **flag** `status:needs-attention` \u2014 never auto-corrected |",
|
|
14206
|
+
...renderIssueTypeAssignmentStep(),
|
|
14207
|
+
"5. Each downstream issue includes `Depends on:` linking to its predecessor",
|
|
14208
|
+
"6. Commit and push the extraction file",
|
|
13565
14209
|
"",
|
|
13566
|
-
"
|
|
13567
|
-
"`type:*` label owned by another bundle carries real routing",
|
|
13568
|
-
"information, so the sweep refuses to guess and hands the issue to a",
|
|
13569
|
-
"human instead. Ambiguity is narrower than it looks: all three",
|
|
13570
|
-
"requirements bundles declare `type:requirement`, so every `req:*`",
|
|
13571
|
-
"phase label resolves to the same type label \u2014 genuine ambiguity",
|
|
13572
|
-
"needs phase labels from two bundles with *different* type labels.",
|
|
14210
|
+
"## Input",
|
|
13573
14211
|
"",
|
|
13574
|
-
"
|
|
13575
|
-
"
|
|
13576
|
-
"
|
|
13577
|
-
"
|
|
13578
|
-
].join("\n");
|
|
13579
|
-
}
|
|
13580
|
-
function isPhaseLabelMatcherOwnedByExcluded(matcher, excludeBundles) {
|
|
13581
|
-
if (excludeBundles.length === 0) {
|
|
13582
|
-
return false;
|
|
13583
|
-
}
|
|
13584
|
-
let owned = false;
|
|
13585
|
-
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
13586
|
-
if (!ownership.phaseLabelPrefixes.includes(matcher)) {
|
|
13587
|
-
continue;
|
|
13588
|
-
}
|
|
13589
|
-
owned = true;
|
|
13590
|
-
if (!excludeBundles.includes(bundleName)) {
|
|
13591
|
-
return false;
|
|
13592
|
-
}
|
|
13593
|
-
}
|
|
13594
|
-
return owned;
|
|
13595
|
-
}
|
|
13596
|
-
function renderPhaseTypeInvariantShellHelpers() {
|
|
13597
|
-
const matchers = Object.keys(PHASE_LABEL_TYPE_MAP);
|
|
13598
|
-
const exactMatchers = matchers.filter((m) => !m.endsWith(":")).sort();
|
|
13599
|
-
const prefixMatchers = matchers.filter((m) => m.endsWith(":")).sort((a, b) => b.length - a.length || a.localeCompare(b));
|
|
13600
|
-
const lines = [
|
|
13601
|
-
"# Resolve ONE phase label to the `type:<bundle>` label its owning",
|
|
13602
|
-
"# bundle declares. Echoes the label (with the `type:` prefix) or",
|
|
13603
|
-
"# nothing when no bundle owns it. Exact-match branches come first,",
|
|
13604
|
-
"# so `req:write` (requirements-writer) beats the `req:` prefix",
|
|
13605
|
-
"# (requirements-analyst). Generated from BUNDLE_OWNERSHIP \u2014 do not",
|
|
13606
|
-
"# hand-edit.",
|
|
13607
|
-
"phase_label_type_of() {",
|
|
13608
|
-
' case "${1:-}" in'
|
|
13609
|
-
];
|
|
13610
|
-
for (const matcher of exactMatchers) {
|
|
13611
|
-
lines.push(` ${matcher}) echo "${PHASE_LABEL_TYPE_MAP[matcher]}" ;;`);
|
|
13612
|
-
}
|
|
13613
|
-
for (const matcher of prefixMatchers) {
|
|
13614
|
-
lines.push(` ${matcher}*) echo "${PHASE_LABEL_TYPE_MAP[matcher]}" ;;`);
|
|
13615
|
-
}
|
|
13616
|
-
lines.push(
|
|
13617
|
-
" *) : ;;",
|
|
13618
|
-
" esac",
|
|
13619
|
-
"}",
|
|
14212
|
+
"Provide a path to a file in either `notes/` or `transcripts/`. The",
|
|
14213
|
+
"agent will look up the sibling automatically via basename match. A",
|
|
14214
|
+
"missing sibling is a normal case (notes-only or transcript-only) \u2014",
|
|
14215
|
+
"the agent handles all three input cases.",
|
|
13620
14216
|
"",
|
|
13621
|
-
"
|
|
13622
|
-
"# label \u2014 the ONLY type labels the invariant correction may remove.",
|
|
13623
|
-
"# A `type:*` label owned by another bundle is never removed; the",
|
|
13624
|
-
"# issue is flagged for human triage instead.",
|
|
13625
|
-
"is_conventional_type_label() {",
|
|
13626
|
-
` case "\${1:-}" in`,
|
|
13627
|
-
` ${CONVENTIONAL_COMMIT_TYPE_LABELS.join("|")}) return 0 ;;`,
|
|
13628
|
-
" *) return 1 ;;",
|
|
13629
|
-
" esac",
|
|
13630
|
-
"}",
|
|
14217
|
+
"## Output",
|
|
13631
14218
|
"",
|
|
13632
|
-
"
|
|
13633
|
-
"
|
|
13634
|
-
"
|
|
13635
|
-
"
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
const ownership = BUNDLE_OWNERSHIP[bundleName];
|
|
13701
|
-
if (!ownership) {
|
|
13702
|
-
continue;
|
|
13703
|
-
}
|
|
13704
|
-
if (ownership.typeLabels.includes(typeLabel)) {
|
|
13705
|
-
const owners = findOwnersOfTypeLabel(typeLabel);
|
|
13706
|
-
const allExcluded = owners.every(
|
|
13707
|
-
(owner) => excludedBundles.includes(owner)
|
|
13708
|
-
);
|
|
13709
|
-
if (allExcluded) {
|
|
13710
|
-
return true;
|
|
14219
|
+
"- A structured extraction at",
|
|
14220
|
+
" `<meetingsRoot>/insights/{type}/<basename>.md`",
|
|
14221
|
+
"- Phase issues with `meeting:*` labels for downstream agent sessions",
|
|
14222
|
+
" to pick up (notes, draft, link)"
|
|
14223
|
+
].join("\n")
|
|
14224
|
+
};
|
|
14225
|
+
function buildMeetingAnalysisBundle(tier = AGENT_MODEL.BALANCED) {
|
|
14226
|
+
return {
|
|
14227
|
+
name: "meeting-analysis",
|
|
14228
|
+
description: "Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)",
|
|
14229
|
+
appliesWhen: () => true,
|
|
14230
|
+
rules: [
|
|
14231
|
+
{
|
|
14232
|
+
name: "meeting-processing-workflow",
|
|
14233
|
+
description: "Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions",
|
|
14234
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
14235
|
+
content: [
|
|
14236
|
+
"# Meeting Processing Workflow",
|
|
14237
|
+
"",
|
|
14238
|
+
"Use `/process-meeting <path>` to process a meeting through a",
|
|
14239
|
+
"4-phase pipeline (extract \u2192 notes \u2192 draft \u2192 link). Each phase runs as a",
|
|
14240
|
+
"separate agent session tracked by a GitHub issue with a `meeting:*` label.",
|
|
14241
|
+
"See the `meeting-analyst` agent definition for full workflow details.",
|
|
14242
|
+
"",
|
|
14243
|
+
"Meeting artifacts live in **three parallel trees** rooted at the",
|
|
14244
|
+
"project's meetings root:",
|
|
14245
|
+
"",
|
|
14246
|
+
"- `transcripts/{internal,external}/` \u2014 verbatim transcripts (evidence)",
|
|
14247
|
+
"- `notes/{internal,external}/` \u2014 curated narrative summary",
|
|
14248
|
+
" (input + Phase 2 output)",
|
|
14249
|
+
"- `insights/{internal,external}/` \u2014 structured extraction (Phase 1 output)",
|
|
14250
|
+
"",
|
|
14251
|
+
"The three trees share identical basenames so a meeting's siblings",
|
|
14252
|
+
"are looked up by filename, not by frontmatter cross-references.",
|
|
14253
|
+
"Phase 1 accepts every input case (notes + transcript, notes only,",
|
|
14254
|
+
"or transcript only) and Phase 2 enhances the notes file in place",
|
|
14255
|
+
"rather than authoring it from scratch.",
|
|
14256
|
+
"",
|
|
14257
|
+
"Notes and insights files may carry optional frontmatter fields",
|
|
14258
|
+
"`slug`, `source`, `transcript_available`, and `confidence`",
|
|
14259
|
+
"alongside the existing `meeting_type` and `areas` fields. Missing",
|
|
14260
|
+
"frontmatter is treated as a normal input case \u2014 never fail-loud.",
|
|
14261
|
+
"",
|
|
14262
|
+
"Meeting notes may declare a `meeting_type` (one of the project's",
|
|
14263
|
+
"recognized types) and an `areas: [...]` list. The `meeting_type`",
|
|
14264
|
+
"resolves to a generic kind \u2014 `planning` / `review` / `brainstorm` /",
|
|
14265
|
+
"`standup` / `external` / `other` \u2014 that drives type-specific",
|
|
14266
|
+
"extraction rules in phases 1\u20132. The `areas` list scopes phase-4",
|
|
14267
|
+
"direct edits to the doc-root sub-folders declared in the project's",
|
|
14268
|
+
"**Area \u2192 doc-root mapping** table. When both fields are absent",
|
|
14269
|
+
"the pipeline falls back to the default workflow (kind `other`,",
|
|
14270
|
+
"no area gating).",
|
|
14271
|
+
"",
|
|
14272
|
+
"Phase 4 applies an **agent-workability split** to action items:",
|
|
14273
|
+
"items that yield a documentation deliverable an agent can author",
|
|
14274
|
+
"are filed through their dedicated downstream channel",
|
|
14275
|
+
"(`req:write`, `docs:write`, `bcm:*`, `research:scope`, roadmap",
|
|
14276
|
+
"follow-up); human-owned tasks (send / schedule / install /",
|
|
14277
|
+
"decide / communicate / get-access / build-elsewhere) are",
|
|
14278
|
+
"recorded **only** in the notes `## Action Items` table, which is",
|
|
14279
|
+
"the **system of record for human follow-ups** \u2014 no GitHub issue",
|
|
14280
|
+
"is filed for them. Consumers tune or disable the split via",
|
|
14281
|
+
"`AgentConfigOptions.meetings.actionItemFiling`."
|
|
14282
|
+
].join("\n"),
|
|
14283
|
+
platforms: {
|
|
14284
|
+
cursor: { exclude: true }
|
|
14285
|
+
},
|
|
14286
|
+
tags: ["workflow"]
|
|
13711
14287
|
}
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
}
|
|
13731
|
-
|
|
14288
|
+
],
|
|
14289
|
+
skills: [processMeetingSkill],
|
|
14290
|
+
subAgents: [buildMeetingAnalystSubAgent(tier)],
|
|
14291
|
+
labels: [
|
|
14292
|
+
{
|
|
14293
|
+
name: "type:meeting-processing",
|
|
14294
|
+
color: "5319E7",
|
|
14295
|
+
description: "Meeting transcript processing pipeline"
|
|
14296
|
+
},
|
|
14297
|
+
{
|
|
14298
|
+
name: "meeting:extract",
|
|
14299
|
+
color: "C5DEF5",
|
|
14300
|
+
description: "Phase 1: raw extraction from a meeting transcript"
|
|
14301
|
+
},
|
|
14302
|
+
{
|
|
14303
|
+
name: "meeting:notes",
|
|
14304
|
+
color: "BFDADC",
|
|
14305
|
+
description: "Phase 2: curated notes derived from an extraction"
|
|
14306
|
+
},
|
|
14307
|
+
{
|
|
14308
|
+
name: "meeting:draft",
|
|
14309
|
+
color: "D4C5F9",
|
|
14310
|
+
description: "Phase 3: draft follow-up issues proposed from notes"
|
|
14311
|
+
},
|
|
14312
|
+
{
|
|
14313
|
+
name: "meeting:link",
|
|
14314
|
+
color: "FEF2C0",
|
|
14315
|
+
description: "Phase 4: linking/reconciling drafted issues with existing work"
|
|
13732
14316
|
}
|
|
13733
|
-
|
|
13734
|
-
}
|
|
13735
|
-
return false;
|
|
13736
|
-
}
|
|
13737
|
-
function isScheduledTaskOwnedByExcluded(taskId, excludedBundles) {
|
|
13738
|
-
if (excludedBundles.length === 0) {
|
|
13739
|
-
return false;
|
|
13740
|
-
}
|
|
13741
|
-
for (const bundleName of excludedBundles) {
|
|
13742
|
-
const ownership = BUNDLE_OWNERSHIP[bundleName];
|
|
13743
|
-
if (!ownership) {
|
|
13744
|
-
continue;
|
|
13745
|
-
}
|
|
13746
|
-
if (ownership.scheduledTaskIds.includes(taskId)) {
|
|
13747
|
-
return true;
|
|
13748
|
-
}
|
|
13749
|
-
}
|
|
13750
|
-
return false;
|
|
13751
|
-
}
|
|
13752
|
-
function hasAnyDocsEmittingBundle(excludedBundles) {
|
|
13753
|
-
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
13754
|
-
if (!ownership.emitsDocs) {
|
|
13755
|
-
continue;
|
|
13756
|
-
}
|
|
13757
|
-
if (!excludedBundles.includes(bundleName)) {
|
|
13758
|
-
return true;
|
|
13759
|
-
}
|
|
13760
|
-
}
|
|
13761
|
-
return false;
|
|
13762
|
-
}
|
|
13763
|
-
function hasAnyDownstreamIssueKindBundle(excludedBundles) {
|
|
13764
|
-
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
13765
|
-
if (!ownership.downstreamIssueKinds) {
|
|
13766
|
-
continue;
|
|
13767
|
-
}
|
|
13768
|
-
if (!excludedBundles.includes(bundleName)) {
|
|
13769
|
-
return true;
|
|
13770
|
-
}
|
|
13771
|
-
}
|
|
13772
|
-
return false;
|
|
13773
|
-
}
|
|
13774
|
-
function findOwnersOfTypeLabel(typeLabel) {
|
|
13775
|
-
const owners = [];
|
|
13776
|
-
for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
|
|
13777
|
-
if (ownership.typeLabels.includes(typeLabel)) {
|
|
13778
|
-
owners.push(bundleName);
|
|
13779
|
-
}
|
|
13780
|
-
}
|
|
13781
|
-
return owners;
|
|
14317
|
+
]
|
|
14318
|
+
};
|
|
13782
14319
|
}
|
|
14320
|
+
var meetingAnalysisBundle = buildMeetingAnalysisBundle();
|
|
13783
14321
|
|
|
13784
14322
|
// src/agent/bundles/run-ratio.ts
|
|
13785
14323
|
var DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO = 4;
|
|
@@ -19416,6 +19954,8 @@ function buildPeopleProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
19416
19954
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
19417
19955
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
19418
19956
|
"",
|
|
19957
|
+
...renderIssueTypeAssignmentStep(),
|
|
19958
|
+
"",
|
|
19419
19959
|
" The issue body must include:",
|
|
19420
19960
|
" - A **discovery source** line naming this person profile",
|
|
19421
19961
|
" (`Discovered while profiling: <person name>`)",
|
|
@@ -19436,6 +19976,8 @@ function buildPeopleProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
19436
19976
|
` - \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\``,
|
|
19437
19977
|
` - \`status:${labelsForPhase(issueDefaults, "software:research").status}\``,
|
|
19438
19978
|
"",
|
|
19979
|
+
...renderIssueTypeAssignmentStep(),
|
|
19980
|
+
"",
|
|
19439
19981
|
" The issue body must include:",
|
|
19440
19982
|
" - A **discovery source** line naming this person profile",
|
|
19441
19983
|
" (`Discovered while profiling: <person name>`)",
|
|
@@ -19718,6 +20260,8 @@ function buildProfilePersonSkill(paths, issueDefaults) {
|
|
|
19718
20260
|
` \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "people:research").status}\`. Body must include the`,
|
|
19719
20261
|
" person's name, selected role, primary company, framing, and any",
|
|
19720
20262
|
" overrides.",
|
|
20263
|
+
"",
|
|
20264
|
+
...renderIssueTypeAssignmentStep(),
|
|
19721
20265
|
"2. Execute Phase 1 (Research) of the people-profile-analyst agent.",
|
|
19722
20266
|
"3. Phase 1 creates the `people:draft` issue. Phase 2 may create a",
|
|
19723
20267
|
" `people:followup` issue. Each downstream issue declares its",
|
|
@@ -19809,6 +20353,8 @@ function buildRefreshPersonSkill(paths, issueDefaults) {
|
|
|
19809
20353
|
"1. Create a `people:refresh` issue with `type:people-profile`,",
|
|
19810
20354
|
` \`priority:${labelsForPhase(issueDefaults, "people:refresh").priority}\`, and \`status:${labelsForPhase(issueDefaults, "people:refresh").status}\`. Body must include the`,
|
|
19811
20355
|
" profile path and any overrides.",
|
|
20356
|
+
"",
|
|
20357
|
+
...renderIssueTypeAssignmentStep(),
|
|
19812
20358
|
"2. Execute Phase 4 (Refresh) of the people-profile-analyst agent.",
|
|
19813
20359
|
"",
|
|
19814
20360
|
"## Output",
|
|
@@ -23505,6 +24051,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
23505
24051
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
23506
24052
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
23507
24053
|
"",
|
|
24054
|
+
...renderIssueTypeAssignmentStep(),
|
|
24055
|
+
"",
|
|
23508
24056
|
"9. **Verify all handoffs were created** before committing.",
|
|
23509
24057
|
"",
|
|
23510
24058
|
"10. **Commit and push** the regulation page. Close the research",
|
|
@@ -23615,6 +24163,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
23615
24163
|
` - \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\``,
|
|
23616
24164
|
` - \`status:${labelsForPhase(issueDefaults, "req:scan").status}\``,
|
|
23617
24165
|
"",
|
|
24166
|
+
...renderIssueTypeAssignmentStep(),
|
|
24167
|
+
"",
|
|
23618
24168
|
" The body must also:",
|
|
23619
24169
|
" - Identify the target category as **SEC** (security & compliance)",
|
|
23620
24170
|
" in the body so the downstream writer phase picks up the right",
|
|
@@ -23634,6 +24184,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
23634
24184
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
23635
24185
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
23636
24186
|
"",
|
|
24187
|
+
...renderIssueTypeAssignmentStep(),
|
|
24188
|
+
"",
|
|
23637
24189
|
"6. **Create `people:research` issues** for notable regulatory",
|
|
23638
24190
|
" leaders (commissioners, agency directors, lead policy authors)",
|
|
23639
24191
|
" mentioned on the regulation page. Keep this list small \u2014 at most",
|
|
@@ -23645,6 +24197,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
23645
24197
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
23646
24198
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
23647
24199
|
"",
|
|
24200
|
+
...renderIssueTypeAssignmentStep(),
|
|
24201
|
+
"",
|
|
23648
24202
|
"7. **Commit and push** the updated regulation page. Close the",
|
|
23649
24203
|
" impact issue.",
|
|
23650
24204
|
"",
|
|
@@ -23812,6 +24366,8 @@ function buildScanRegulatoryLandscapeSkill(paths, issueDefaults) {
|
|
|
23812
24366
|
` \`priority:${labelsForPhase(issueDefaults, "regulatory:scan").priority}\`, and \`status:${labelsForPhase(issueDefaults, "regulatory:scan").status}\`. The body must include the`,
|
|
23813
24367
|
" scope slug, the scope type, and any known regulations to include",
|
|
23814
24368
|
" or exclude.",
|
|
24369
|
+
"",
|
|
24370
|
+
...renderIssueTypeAssignmentStep(),
|
|
23815
24371
|
"2. Execute Phase 1 (Scan) of the regulatory-research-analyst agent.",
|
|
23816
24372
|
"3. Phase 1 writes the scan report and creates one",
|
|
23817
24373
|
" `regulatory:research` issue per prioritized regulation.",
|
|
@@ -23888,6 +24444,8 @@ function buildResearchRegulationSkill(paths, issueDefaults) {
|
|
|
23888
24444
|
` \`type:regulatory-research\`, \`priority:${labelsForPhase(issueDefaults, "regulatory:research").priority}\`, and`,
|
|
23889
24445
|
` \`status:${labelsForPhase(issueDefaults, "regulatory:research").status}\`. The body must include the scope slug and the`,
|
|
23890
24446
|
" regulation slug.",
|
|
24447
|
+
"",
|
|
24448
|
+
...renderIssueTypeAssignmentStep(),
|
|
23891
24449
|
"2. Execute Phase 2 (Research) of the regulatory-research-analyst",
|
|
23892
24450
|
" agent. The agent runs 6\u201312 targeted web searches and populates",
|
|
23893
24451
|
" the regulation page.",
|
|
@@ -23955,6 +24513,8 @@ function buildImpactRegulationSkill(paths, issueDefaults) {
|
|
|
23955
24513
|
` \`status:${labelsForPhase(issueDefaults, "regulatory:impact").status}\` (or \`status:blocked\` when still dependent on a`,
|
|
23956
24514
|
" Phase 2 research issue). Body must include the regulation page",
|
|
23957
24515
|
" path.",
|
|
24516
|
+
"",
|
|
24517
|
+
...renderIssueTypeAssignmentStep(),
|
|
23958
24518
|
"2. Execute Phase 3 (Impact) of the regulatory-research-analyst",
|
|
23959
24519
|
" agent. No web searches \u2014 pure synthesis from the regulation",
|
|
23960
24520
|
" page and project context.",
|
|
@@ -26790,6 +27350,8 @@ function buildWriteRequirementSkill(paths, issueDefaults) {
|
|
|
26790
27350
|
" Body must include the category, tier, output path, and a pointer",
|
|
26791
27351
|
" to the upstream proposal (or a direct user description if no",
|
|
26792
27352
|
" proposals file exists).",
|
|
27353
|
+
"",
|
|
27354
|
+
...renderIssueTypeAssignmentStep(),
|
|
26793
27355
|
"2. Execute the write phase of the requirements-writer agent.",
|
|
26794
27356
|
"3. The agent writes one requirement document, updates the category",
|
|
26795
27357
|
" index, opens a PR, and closes the issue.",
|
|
@@ -27379,6 +27941,8 @@ function buildRequirementsAnalystSubAgent(paths, issueDefaults) {
|
|
|
27379
27941
|
` \`--label "tier:<tier-slug>"\`, \`--label "status:${labelsForPhase(issueDefaults, "req:write").status}"\`, and`,
|
|
27380
27942
|
` \`--label "priority:${labelsForPhase(issueDefaults, "req:write").priority}"\`.`,
|
|
27381
27943
|
"",
|
|
27944
|
+
...renderIssueTypeAssignmentStep(),
|
|
27945
|
+
"",
|
|
27382
27946
|
" The body must carry the three writer-required fields in an",
|
|
27383
27947
|
" `## Objective` block, written as bold-prefixed lines so the",
|
|
27384
27948
|
" writer's intake parser can pull them out, plus the reserved-ID",
|
|
@@ -27525,6 +28089,8 @@ function buildScanRequirementsSkill(issueDefaults) {
|
|
|
27525
28089
|
"",
|
|
27526
28090
|
`1. Create a \`req:scan\` issue with \`type:requirement\`, \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\`,`,
|
|
27527
28091
|
` and \`status:${labelsForPhase(issueDefaults, "req:scan").status}\`. Body must list the files to read and the scan scope.`,
|
|
28092
|
+
"",
|
|
28093
|
+
...renderIssueTypeAssignmentStep(),
|
|
27528
28094
|
"2. Execute Phase 1 (Scan) of the requirements-analyst agent.",
|
|
27529
28095
|
"3. If gaps are found, a `req:draft-trace` issue is created automatically.",
|
|
27530
28096
|
"",
|
|
@@ -28573,6 +29139,7 @@ function buildRequirementsReviewerSubAgent(paths, issueDefaults) {
|
|
|
28573
29139
|
"- Labels: `type:requirement`, `req:write`, the matching",
|
|
28574
29140
|
" `tier:*` label derived from the referencing document's Tier,",
|
|
28575
29141
|
` \`priority:${labelsForPhase(issueDefaults, "req:write").priority}\`, \`status:${labelsForPhase(issueDefaults, "req:write").status}\`.`,
|
|
29142
|
+
...renderIssueTypeAssignmentStep({ indent: "", bullet: true }),
|
|
28576
29143
|
"- If any of Category / Tier / Output Path cannot be derived from",
|
|
28577
29144
|
" the referencing document, open the follow-up with",
|
|
28578
29145
|
" `status:needs-attention` and a `Missing:` line, per the same",
|
|
@@ -28728,6 +29295,8 @@ function buildReviewRequirementsSkill(paths, issueDefaults) {
|
|
|
28728
29295
|
` \`priority:${labelsForPhase(issueDefaults, "req:review").priority}\`, and \`status:${labelsForPhase(issueDefaults, "req:review").status}\`. Body must include the`,
|
|
28729
29296
|
" scope, the requirements root (or accept the default), and the",
|
|
28730
29297
|
" output path.",
|
|
29298
|
+
"",
|
|
29299
|
+
...renderIssueTypeAssignmentStep(),
|
|
28731
29300
|
"2. Execute the review phase of the requirements-reviewer agent.",
|
|
28732
29301
|
"3. The agent runs the 12-check audit, writes a structured report",
|
|
28733
29302
|
" grouped by Critical / Warning / Info (plus a separate",
|
|
@@ -28830,6 +29399,8 @@ function buildDeprecateRequirementSkill(_paths, issueDefaults) {
|
|
|
28830
29399
|
` \`priority:${labelsForPhase(issueDefaults, "req:deprecate").priority}\`, and \`status:${labelsForPhase(issueDefaults, "req:deprecate").status}\`. Body must include the`,
|
|
28831
29400
|
" Targets, Transition, and Reason sections above (optionally",
|
|
28832
29401
|
" `Pre-approved: yes`).",
|
|
29402
|
+
"",
|
|
29403
|
+
...renderIssueTypeAssignmentStep(),
|
|
28833
29404
|
"2. Execute the deprecation phase of the requirements-reviewer",
|
|
28834
29405
|
" agent.",
|
|
28835
29406
|
"3. The agent verifies inputs, pauses for human confirmation (or",
|
|
@@ -29404,6 +29975,8 @@ function buildResearchSkill(paths, issueDefaults) {
|
|
|
29404
29975
|
"1. Create a `research:scope` issue with `type:research`,",
|
|
29405
29976
|
` \`priority:${labelsForPhase(issueDefaults, "research:scope").priority}\`, and \`status:${labelsForPhase(issueDefaults, "research:scope").status}\`. Body must include the`,
|
|
29406
29977
|
" verbatim question, authorized sources, and any overrides.",
|
|
29978
|
+
"",
|
|
29979
|
+
...renderIssueTypeAssignmentStep(),
|
|
29407
29980
|
"2. Execute Phase 1 (Scope) of the research-analyst agent.",
|
|
29408
29981
|
"3. Phase 1 creates `research:slice` issues (one per slice) and a",
|
|
29409
29982
|
" single `research:verify` issue. Each downstream issue declares",
|
|
@@ -30219,6 +30792,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
30219
30792
|
` - \`priority:${labelsForPhase(issueDefaults, "bcm:outline").priority}\``,
|
|
30220
30793
|
` - \`status:${labelsForPhase(issueDefaults, "bcm:outline").status}\``,
|
|
30221
30794
|
"",
|
|
30795
|
+
...renderIssueTypeAssignmentStep(),
|
|
30796
|
+
"",
|
|
30222
30797
|
" The issue body must include:",
|
|
30223
30798
|
" - A **discovery source** line naming this software profile",
|
|
30224
30799
|
" (`Discovered while mapping: <product name>`)",
|
|
@@ -30287,6 +30862,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
30287
30862
|
" `software:research` phase with `type:software-profile`,",
|
|
30288
30863
|
` \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:research").status}\`.`,
|
|
30289
30864
|
"",
|
|
30865
|
+
...renderIssueTypeAssignmentStep(),
|
|
30866
|
+
"",
|
|
30290
30867
|
"3. **Enqueue a `company:research` issue for the vendor company** if",
|
|
30291
30868
|
" no matching profile already exists under `<COMPANY_PROFILES_DIR>/`.",
|
|
30292
30869
|
" The vendor (the company that builds or maintains the product)",
|
|
@@ -30299,6 +30876,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
30299
30876
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
30300
30877
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
30301
30878
|
"",
|
|
30879
|
+
...renderIssueTypeAssignmentStep(),
|
|
30880
|
+
"",
|
|
30302
30881
|
" The issue body must include:",
|
|
30303
30882
|
" - A **discovery source** line naming this software profile",
|
|
30304
30883
|
" (`Discovered while profiling: <product name>`)",
|
|
@@ -30318,6 +30897,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
|
|
|
30318
30897
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
30319
30898
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
30320
30899
|
"",
|
|
30900
|
+
...renderIssueTypeAssignmentStep(),
|
|
30901
|
+
"",
|
|
30321
30902
|
" The issue body must include:",
|
|
30322
30903
|
" - A **discovery source** line naming this software profile",
|
|
30323
30904
|
" (`Discovered while profiling: <product name>`)",
|
|
@@ -30508,6 +31089,8 @@ function buildProfileSoftwareSkill(paths, issueDefaults) {
|
|
|
30508
31089
|
"1. Create a `software:research` issue with `type:software-profile`,",
|
|
30509
31090
|
` \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:research").status}\`. Body must include the`,
|
|
30510
31091
|
" product name, selected type, framing, and any overrides.",
|
|
31092
|
+
"",
|
|
31093
|
+
...renderIssueTypeAssignmentStep(),
|
|
30511
31094
|
"2. Execute Phase 1 (Research) of the software-profile-analyst",
|
|
30512
31095
|
" agent.",
|
|
30513
31096
|
"3. Phase 1 creates the `software:profile` issue. Phase 2 creates",
|
|
@@ -30596,6 +31179,8 @@ function buildMapSoftwareSkill(paths, issueDefaults) {
|
|
|
30596
31179
|
"1. Create a `software:map` issue with `type:software-profile`,",
|
|
30597
31180
|
` \`priority:${labelsForPhase(issueDefaults, "software:map").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:map").status}\`. Body must include the`,
|
|
30598
31181
|
" profile path and any overrides.",
|
|
31182
|
+
"",
|
|
31183
|
+
...renderIssueTypeAssignmentStep(),
|
|
30599
31184
|
"2. Execute Phase 4 (Map) of the software-profile-analyst agent.",
|
|
30600
31185
|
"3. Phase 4 writes the `## Capability Mapping` section, enqueues",
|
|
30601
31186
|
" `bcm:outline` issues for unmapped features above the threshold,",
|
|
@@ -31208,6 +31793,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
31208
31793
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
31209
31794
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
31210
31795
|
"",
|
|
31796
|
+
...renderIssueTypeAssignmentStep(),
|
|
31797
|
+
"",
|
|
31211
31798
|
"6. **Create `people:research` issues** for every entry in *People of",
|
|
31212
31799
|
" Interest* that does not already have a canonical person profile",
|
|
31213
31800
|
" or an open `people:research` issue. The `people-profile` bundle",
|
|
@@ -31219,6 +31806,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
31219
31806
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
31220
31807
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
31221
31808
|
"",
|
|
31809
|
+
...renderIssueTypeAssignmentStep(),
|
|
31810
|
+
"",
|
|
31222
31811
|
"7. **Verify all handoffs were created** before committing. For each",
|
|
31223
31812
|
" entity in both tables, confirm an existing profile or a fresh",
|
|
31224
31813
|
" handoff issue exists. Do not commit with missing handoffs.",
|
|
@@ -31512,6 +32101,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
31512
32101
|
` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
|
|
31513
32102
|
` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
|
|
31514
32103
|
"",
|
|
32104
|
+
...renderIssueTypeAssignmentStep(),
|
|
32105
|
+
"",
|
|
31515
32106
|
"6. **Hand off canonical people profiles** by creating one",
|
|
31516
32107
|
" `people:research` issue per leadership entry that does not",
|
|
31517
32108
|
" already have a canonical profile or an open `people:research`",
|
|
@@ -31523,6 +32114,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
|
|
|
31523
32114
|
` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
|
|
31524
32115
|
` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
|
|
31525
32116
|
"",
|
|
32117
|
+
...renderIssueTypeAssignmentStep(),
|
|
32118
|
+
"",
|
|
31526
32119
|
"7. **Commit and push** the organization page. Close the",
|
|
31527
32120
|
" organizations issue.",
|
|
31528
32121
|
"",
|
|
@@ -31697,6 +32290,8 @@ function buildScopeStandardsResearchSkill(paths, issueDefaults) {
|
|
|
31697
32290
|
` \`priority:${labelsForPhase(issueDefaults, "standards:scope").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:scope").status}\`. The body must include the`,
|
|
31698
32291
|
" standard slug, the list of target versions (or a request to",
|
|
31699
32292
|
" enumerate), and any known governance bodies.",
|
|
32293
|
+
"",
|
|
32294
|
+
...renderIssueTypeAssignmentStep(),
|
|
31700
32295
|
"2. Execute Phase 1 (Scope) of the standards-research-analyst agent.",
|
|
31701
32296
|
"3. Phase 1 writes the query plan and creates one `standards:research`",
|
|
31702
32297
|
" issue per target version, one `standards:compare` issue (blocked",
|
|
@@ -31761,6 +32356,8 @@ function buildResearchStandardSkill(paths, issueDefaults) {
|
|
|
31761
32356
|
"1. Create a `standards:research` issue with",
|
|
31762
32357
|
` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:research").status}\`.`,
|
|
31763
32358
|
" The body must include the standard slug and the version slug.",
|
|
32359
|
+
"",
|
|
32360
|
+
...renderIssueTypeAssignmentStep(),
|
|
31764
32361
|
"2. Execute Phase 2 (Research) of the standards-research-analyst",
|
|
31765
32362
|
" agent. The agent runs 6\u201310 targeted web searches and populates",
|
|
31766
32363
|
" the version page.",
|
|
@@ -31834,6 +32431,8 @@ function buildCompareStandardsSkill(paths, issueDefaults) {
|
|
|
31834
32431
|
` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:compare").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:compare").status}\`.`,
|
|
31835
32432
|
" Body must include the standard slug and the list of version",
|
|
31836
32433
|
" pages under comparison.",
|
|
32434
|
+
"",
|
|
32435
|
+
...renderIssueTypeAssignmentStep(),
|
|
31837
32436
|
"2. Execute Phase 3 (Compare) of the standards-research-analyst",
|
|
31838
32437
|
" agent. No web searches \u2014 pure synthesis from the version pages.",
|
|
31839
32438
|
"",
|
|
@@ -31902,6 +32501,8 @@ function buildExtensionStandardSkill(paths, issueDefaults) {
|
|
|
31902
32501
|
" The body must include the standard slug, the entity slug, the",
|
|
31903
32502
|
" closest resource, and a link to the source BCM or canvas",
|
|
31904
32503
|
" document.",
|
|
32504
|
+
"",
|
|
32505
|
+
...renderIssueTypeAssignmentStep(),
|
|
31905
32506
|
"2. Execute Phase 4 (Extension) of the standards-research-analyst",
|
|
31906
32507
|
" agent. The agent runs 4\u20138 targeted web searches against",
|
|
31907
32508
|
" community registries, implementation guides, and working-group",
|
|
@@ -31967,6 +32568,8 @@ function buildOrganizationsStandardSkill(paths, issueDefaults) {
|
|
|
31967
32568
|
` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:organizations").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:organizations").status}\`.`,
|
|
31968
32569
|
" Body must include the standard slug, the organization slug, and",
|
|
31969
32570
|
" the organization's governance role.",
|
|
32571
|
+
"",
|
|
32572
|
+
...renderIssueTypeAssignmentStep(),
|
|
31970
32573
|
"2. Execute Phase 5 (Organizations) of the",
|
|
31971
32574
|
" standards-research-analyst agent. The agent runs 4\u20138 targeted",
|
|
31972
32575
|
" web searches.",
|
|
@@ -32276,6 +32879,14 @@ var UPSTREAM_CONFIGULATOR_DOCS_SUMMARY = [
|
|
|
32276
32879
|
"",
|
|
32277
32880
|
"Pick the `type:*` and matching prefix that describes the work (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`). Set `priority:*` from the urgency and use `status:blocked` instead of `status:ready` if the issue depends on another open issue.",
|
|
32278
32881
|
"",
|
|
32882
|
+
"Then set the new issue's **GitHub issue type** \u2014 a separate field from the `type:*` label, which `gh issue create` cannot set. Derive it from the title prefix (`epic:` \u2192 Epic, `feat:` \u2192 Feature, `fix:` \u2192 Bug, everything else \u2192 Task). The local `.claude/procedures/set-issue-type.sh` helper resolves owner/repo from the **current** checkout, so a cross-repo filing needs the `updateIssueIssueType` GraphQL flow with an explicit owner/repo:",
|
|
32883
|
+
"",
|
|
32884
|
+
"```sh",
|
|
32885
|
+
"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=codedrifters -f repo=packages",
|
|
32886
|
+
"gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'",
|
|
32887
|
+
"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>",
|
|
32888
|
+
"```",
|
|
32889
|
+
"",
|
|
32279
32890
|
"See `.claude/rules/upstream-configulator-docs-detail.md` for the full reference \u2014 extended `gh` recipes, common pitfalls (rate limits, base64 decoding, search vs. browse), and a complete issue-creation walkthrough."
|
|
32280
32891
|
].join("\n");
|
|
32281
32892
|
var UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [
|
|
@@ -32384,6 +32995,16 @@ var UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [
|
|
|
32384
32995
|
"- `priority:*` \u2014 pick exactly one of `priority:critical`, `priority:high`, `priority:medium`, `priority:low`, `priority:trivial`. Default to `priority:medium` when nothing in the request signals urgency. Use `priority:high` for blockers and `priority:critical` only for outages or release-blocking work.",
|
|
32385
32996
|
"- `status:*` \u2014 `status:ready` for self-contained issues, `status:blocked` when the issue declares `Depends on: #<n>` against another open issue.",
|
|
32386
32997
|
"",
|
|
32998
|
+
"### GitHub issue type",
|
|
32999
|
+
"",
|
|
33000
|
+
"The GitHub **issue type** (Epic / Feature / Bug / Task) is a separate field from the `type:*` label, and `gh issue create` cannot set it. Derive it from the title prefix \u2014 `epic:` \u2192 Epic, `feat:` \u2192 Feature, `fix:` \u2192 Bug, everything else \u2192 Task \u2014 and apply it in a follow-up call. The bundled `.claude/procedures/set-issue-type.sh` helper resolves owner/repo from the **current** checkout, so a cross-repo filing against `codedrifters/packages` uses the `updateIssueIssueType` GraphQL flow with an explicit owner/repo instead:",
|
|
33001
|
+
"",
|
|
33002
|
+
"```sh",
|
|
33003
|
+
"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=codedrifters -f repo=packages",
|
|
33004
|
+
"gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'",
|
|
33005
|
+
"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>",
|
|
33006
|
+
"```",
|
|
33007
|
+
"",
|
|
32387
33008
|
"### Worked example",
|
|
32388
33009
|
"",
|
|
32389
33010
|
"Suppose configulator's `software-profile-analyst` agent prompt is missing a step you need. Instead of forking the prompt locally:",
|
|
@@ -32397,6 +33018,8 @@ var UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [
|
|
|
32397
33018
|
" --body $'## Summary\\n\\nThe `software-profile-analyst` Phase 2 prompt does not capture the vendor pricing tier (free / paid / enterprise), which downstream consumers need for segment matching.\\n\\n## Details\\n\\n- Add a `Pricing tier` field to the profile template at `docs/src/content/docs/agents/software-profile-analyst.md`\\n- Update the Phase 2 instructions to require the field before commit\\n- Add a regression test in `bundles.test.ts`'",
|
|
32398
33019
|
"```",
|
|
32399
33020
|
"",
|
|
33021
|
+
"The call above does **not** set the GitHub issue type \u2014 `gh issue create` cannot. Assign it immediately, in the same session, with the cross-repo GraphQL flow above (`feat:` title \u2192 **Feature**; every other prefix except `epic:` / `fix:` \u2192 **Task**). Skipping it leaves the upstream issue untyped, and nobody comes back for it later.",
|
|
33022
|
+
"",
|
|
32400
33023
|
"After filing, reference the upstream issue from any local workaround so it can be reverted once the upstream fix lands:",
|
|
32401
33024
|
"",
|
|
32402
33025
|
"```typescript",
|
|
@@ -34573,11 +35196,34 @@ var AgentConfig = class _AgentConfig extends Component8 {
|
|
|
34573
35196
|
).split("\n"),
|
|
34574
35197
|
executable: true
|
|
34575
35198
|
});
|
|
35199
|
+
new TextFile4(
|
|
35200
|
+
this,
|
|
35201
|
+
".claude/procedures/check-issue-template-labels.sh",
|
|
35202
|
+
{
|
|
35203
|
+
lines: renderIssueTemplateLabelsCheckerScript(
|
|
35204
|
+
resolvedIssueTemplates
|
|
35205
|
+
).split("\n"),
|
|
35206
|
+
executable: true
|
|
35207
|
+
}
|
|
35208
|
+
);
|
|
34576
35209
|
}
|
|
34577
35210
|
if (resolvedIssueTemplates.emitStarterDoc) {
|
|
34578
35211
|
new SampleFile2(this.project, resolvedIssueTemplates.templatesPath, {
|
|
34579
35212
|
contents: renderIssueTemplatesStarterPage(resolvedIssueTemplates)
|
|
34580
35213
|
});
|
|
35214
|
+
new TextFile4(
|
|
35215
|
+
this,
|
|
35216
|
+
issueTemplatesGeneratedPath(resolvedIssueTemplates.templatesPath),
|
|
35217
|
+
{
|
|
35218
|
+
lines: renderIssueTemplatesGeneratedPage(
|
|
35219
|
+
resolvedIssueTemplates,
|
|
35220
|
+
collectIssueTemplateRecipeStubs(
|
|
35221
|
+
this.activeBundles,
|
|
35222
|
+
resolveIssueDefaults(this.options.issueDefaults)
|
|
35223
|
+
)
|
|
35224
|
+
).split("\n")
|
|
35225
|
+
}
|
|
35226
|
+
);
|
|
34581
35227
|
}
|
|
34582
35228
|
}
|
|
34583
35229
|
const resolvedTemporalFraming = validateTemporalFramingConfig(
|
|
@@ -41195,6 +41841,7 @@ export {
|
|
|
41195
41841
|
DEFAULT_DECOMPOSITION_TEMPLATE,
|
|
41196
41842
|
DEFAULT_DISPATCH_MODEL,
|
|
41197
41843
|
DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO,
|
|
41844
|
+
DEFAULT_GITHUB_ISSUE_TYPE,
|
|
41198
41845
|
DEFAULT_HOUSEKEEPING_MODEL,
|
|
41199
41846
|
DEFAULT_ISSUE_PRIORITY,
|
|
41200
41847
|
DEFAULT_ISSUE_STATUS,
|
|
@@ -41241,6 +41888,9 @@ export {
|
|
|
41241
41888
|
DEFAULT_UNBLOCK_DEPENDENTS_ENABLED,
|
|
41242
41889
|
DEFAULT_UPSTREAM_CONFIGULATOR_ENABLED,
|
|
41243
41890
|
DOCS_SYNC_AUDIT_SCHEMA_VERSION,
|
|
41891
|
+
GITHUB_ISSUE_TYPES,
|
|
41892
|
+
GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX,
|
|
41893
|
+
ISSUE_TEMPLATES_GENERATED_SUFFIX,
|
|
41244
41894
|
JsiiFaker,
|
|
41245
41895
|
LAYOUT_ENFORCEMENT,
|
|
41246
41896
|
LAYOUT_ROOT_BY_PROJECT_TYPE,
|
|
@@ -41265,6 +41915,7 @@ export {
|
|
|
41265
41915
|
ResetTask,
|
|
41266
41916
|
SCHEDULED_TASK_MODEL_VALUES,
|
|
41267
41917
|
SCOPE_CLASS_VALUES,
|
|
41918
|
+
SET_ISSUE_TYPE_HELPER_PATH,
|
|
41268
41919
|
SHARED_EDITING_CONFLICT_STRATEGY_VALUES,
|
|
41269
41920
|
STARLIGHT_ROLE,
|
|
41270
41921
|
SUPPRESSED_WORKFLOW_RULE_NAMES,
|
|
@@ -41335,6 +41986,7 @@ export {
|
|
|
41335
41986
|
checkLinksProcedure,
|
|
41336
41987
|
classifyIssueScope,
|
|
41337
41988
|
classifyRun,
|
|
41989
|
+
collectIssueTemplateRecipeStubs,
|
|
41338
41990
|
companyProfileBundle,
|
|
41339
41991
|
compileFencedSamples,
|
|
41340
41992
|
createApiDiffCheck,
|
|
@@ -41350,6 +42002,7 @@ export {
|
|
|
41350
42002
|
formatLayoutViolation,
|
|
41351
42003
|
formatStarlightSingletonViolation,
|
|
41352
42004
|
getLatestEligibleVersion,
|
|
42005
|
+
githubIssueTypeForTitle,
|
|
41353
42006
|
githubWorkflowBundle,
|
|
41354
42007
|
hasAnyDocsEmittingBundle,
|
|
41355
42008
|
hasAnyDownstreamIssueKindBundle,
|
|
@@ -41359,6 +42012,8 @@ export {
|
|
|
41359
42012
|
isScheduledTaskOwnedByExcluded,
|
|
41360
42013
|
isSuppressedWorkflowRule,
|
|
41361
42014
|
isTypeLabelOwnedByExcluded,
|
|
42015
|
+
issueTemplatesChildGlob,
|
|
42016
|
+
issueTemplatesGeneratedPath,
|
|
41362
42017
|
jestBundle,
|
|
41363
42018
|
labelsForPhase,
|
|
41364
42019
|
maintenanceAuditBundle,
|
|
@@ -41407,10 +42062,16 @@ export {
|
|
|
41407
42062
|
renderCustomDocSections,
|
|
41408
42063
|
renderExtractApiProcedure,
|
|
41409
42064
|
renderFocusSection,
|
|
42065
|
+
renderGithubIssueTypeSection,
|
|
42066
|
+
renderGithubIssueTypeSectionLines,
|
|
42067
|
+
renderIssueTemplateLabelsCheckerScript,
|
|
41410
42068
|
renderIssueTemplatesBundleHook,
|
|
41411
42069
|
renderIssueTemplatesCheckerScript,
|
|
42070
|
+
renderIssueTemplatesGeneratedPage,
|
|
41412
42071
|
renderIssueTemplatesRuleContent,
|
|
41413
42072
|
renderIssueTemplatesStarterPage,
|
|
42073
|
+
renderIssueTypeAssignmentBlanket,
|
|
42074
|
+
renderIssueTypeAssignmentStep,
|
|
41414
42075
|
renderMeetingTypesSection,
|
|
41415
42076
|
renderNextRequirementIdProcedure,
|
|
41416
42077
|
renderPhaseTypeInvariantSection,
|
|
@@ -41427,6 +42088,7 @@ export {
|
|
|
41427
42088
|
renderScheduledTasksSection,
|
|
41428
42089
|
renderScopeGateSection,
|
|
41429
42090
|
renderScopeGateShellHelpers,
|
|
42091
|
+
renderSetIssueTypeFallbackLines,
|
|
41430
42092
|
renderSharedEditingBundleHook,
|
|
41431
42093
|
renderSharedEditingHelperScript,
|
|
41432
42094
|
renderSharedEditingRuleContent,
|
|
@@ -41437,6 +42099,7 @@ export {
|
|
|
41437
42099
|
renderStripToolArtifactTagsProcedure,
|
|
41438
42100
|
renderTemporalFramingCheckerScript,
|
|
41439
42101
|
renderTemporalFramingRuleContent,
|
|
42102
|
+
renderTitlePrefixTypeBullets,
|
|
41440
42103
|
renderUnblockDependentsScript,
|
|
41441
42104
|
renderUnblockDependentsSection,
|
|
41442
42105
|
requirementsAnalystBundle,
|