@codedrifters/configulator 0.0.405 → 0.0.406

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.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",
@@ -1481,6 +2084,14 @@ function renderIssueTemplatesStarterPage(_it) {
1481
2084
  "`status:*` label from the conventions documented in the",
1482
2085
  "`issue-label-conventions` rule.",
1483
2086
  "",
2087
+ "Every recipe also ends with a **GitHub issue type** assignment.",
2088
+ "`gh issue create` cannot set the issue type, so it takes a second",
2089
+ "call \u2014 an issue that skips it stays untyped forever. Derive the type",
2090
+ "from the title prefix (`epic:` \u2192 Epic, `feat:` \u2192 Feature, `fix:` \u2192",
2091
+ "Bug, everything else \u2014 including every bundle-phase prefix \u2014 \u2192",
2092
+ "Task); see **Assigning the GitHub issue type** in the",
2093
+ "`issue-conventions` rule for the command and its fallback.",
2094
+ "",
1484
2095
  "Before creating any profile-style issue (people, companies,",
1485
2096
  "software), run the duplicate check documented in the owning",
1486
2097
  "bundle's rule \u2014 the issue-templates page is a recipe catalogue,",
@@ -1515,6 +2126,13 @@ function renderIssueTemplatesStarterPage(_it) {
1515
2126
  "- [ ] <criterion 1>",
1516
2127
  "- [ ] <criterion 2>",
1517
2128
  '"',
2129
+ "```",
2130
+ "",
2131
+ "Then assign the GitHub issue type (`Task` for a phase-labelled",
2132
+ "title):",
2133
+ "",
2134
+ "```bash",
2135
+ `${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${DEFAULT_GITHUB_ISSUE_TYPE}`,
1518
2136
  "```"
1519
2137
  ].join("\n");
1520
2138
  }
@@ -4619,16 +5237,7 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
4619
5237
  "| `release:` | Release preparation, version bumps |",
4620
5238
  "| `hotfix:` | Urgent production fixes |",
4621
5239
  "",
4622
- "## GitHub Issue Type",
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 |",
5240
+ ...renderGithubIssueTypeSectionLines(),
4632
5241
  "",
4633
5242
  "## Prerequisite Issues",
4634
5243
  "",
@@ -5318,6 +5927,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
5318
5927
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
5319
5928
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
5320
5929
  "",
5930
+ ...renderIssueTypeAssignmentStep(),
5931
+ "",
5321
5932
  " **Unfamiliar company (enabling vendor, partner, competitor).**",
5322
5933
  " Hand off to the `company-profile` bundle by creating a",
5323
5934
  " `company:research` issue. The issue must carry:",
@@ -5327,6 +5938,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
5327
5938
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
5328
5939
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
5329
5940
  "",
5941
+ ...renderIssueTypeAssignmentStep(),
5942
+ "",
5330
5943
  " **Missing research topic (value stream, market sizing, etc.).**",
5331
5944
  " Hand off to the `research-pipeline` bundle by creating a",
5332
5945
  " `research:scope` issue. The issue must carry:",
@@ -5336,6 +5949,8 @@ function buildBcmWriterSubAgent(paths, issueDefaults) {
5336
5949
  ` - \`priority:${labelsForPhase(issueDefaults, "research:scope").priority}\``,
5337
5950
  ` - \`status:${labelsForPhase(issueDefaults, "research:scope").status}\``,
5338
5951
  "",
5952
+ ...renderIssueTypeAssignmentStep(),
5953
+ "",
5339
5954
  " This phase assumes the `people-profile`, `company-profile`, and",
5340
5955
  " `research-pipeline` bundles are enabled in the consuming project.",
5341
5956
  " If a bundle is not enabled, flag the connect issue with",
@@ -5458,6 +6073,8 @@ function buildWriteBcmSkill(paths, issueDefaults) {
5458
6073
  ` \`priority:${labelsForPhase(issueDefaults, "bcm:outline").priority}\`, and \`status:${labelsForPhase(issueDefaults, "bcm:outline").status}\`. Body must include the`,
5459
6074
  " verbatim capability name and any overrides.",
5460
6075
  "",
6076
+ "",
6077
+ ...renderIssueTypeAssignmentStep(),
5461
6078
  "2. Execute Phase 1 (Outline) of the bcm-writer agent.",
5462
6079
  "",
5463
6080
  "3. Phase 1 creates a `bcm:scaffold` issue, which Phase 2 follows with",
@@ -6744,6 +7361,8 @@ function buildScanBusinessModelsSkill(paths, issueDefaults) {
6744
7361
  "1. Create a `business-models:scan` issue with `type:business-model`,",
6745
7362
  ` \`priority:${labelsForPhase(issueDefaults, "business-models:scan").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:scan").status}\`. The body must include the`,
6746
7363
  " industry slug, the source plan path (if any), and any overrides.",
7364
+ "",
7365
+ ...renderIssueTypeAssignmentStep(),
6747
7366
  "2. Execute Phase 1 (Scan) of the business-models-analyst agent.",
6748
7367
  "3. Phase 1 creates one `business-models:canvas` issue per in-scope",
6749
7368
  " segment. Each canvas issue declares its `Depends on:`",
@@ -6818,6 +7437,8 @@ function buildCanvasBusinessModelSkill(paths, issueDefaults) {
6818
7437
  ` \`type:business-model\`, \`priority:${labelsForPhase(issueDefaults, "business-models:canvas").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:canvas").status}\`.`,
6819
7438
  " The body must include the industry slug, segment slug, and any",
6820
7439
  " scan-report reference.",
7440
+ "",
7441
+ ...renderIssueTypeAssignmentStep(),
6821
7442
  "2. Execute Phase 2 (Canvas) of the business-models-analyst agent.",
6822
7443
  "3. Phase 2 writes the nine-block canvas and creates a",
6823
7444
  " `business-models:complete` issue for the downstream Phase 3.",
@@ -6877,6 +7498,8 @@ function buildCompleteBusinessModelSkill(paths, issueDefaults) {
6877
7498
  "1. Create a `business-models:complete` issue with",
6878
7499
  ` \`type:business-model\`, \`priority:${labelsForPhase(issueDefaults, "business-models:complete").priority}\`, and \`status:${labelsForPhase(issueDefaults, "business-models:complete").status}\`.`,
6879
7500
  " Body must include the canvas document path.",
7501
+ "",
7502
+ ...renderIssueTypeAssignmentStep(),
6880
7503
  "2. Execute Phase 3 (Complete) of the business-models-analyst agent.",
6881
7504
  "",
6882
7505
  "## Output",
@@ -7401,6 +8024,8 @@ function buildCompanyProfileAnalystSubAgent(paths, issueDefaults, tier) {
7401
8024
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
7402
8025
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
7403
8026
  "",
8027
+ ...renderIssueTypeAssignmentStep(),
8028
+ "",
7404
8029
  " The issue body must include:",
7405
8030
  " - A **discovery source** line naming this company profile",
7406
8031
  " (`Discovered while profiling: <company name>`)",
@@ -7418,6 +8043,8 @@ function buildCompanyProfileAnalystSubAgent(paths, issueDefaults, tier) {
7418
8043
  ` - \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\``,
7419
8044
  ` - \`status:${labelsForPhase(issueDefaults, "software:research").status}\``,
7420
8045
  "",
8046
+ ...renderIssueTypeAssignmentStep(),
8047
+ "",
7421
8048
  " The issue body must include:",
7422
8049
  " - A **discovery source** line naming this company profile",
7423
8050
  " (`Discovered while profiling: <company name>`)",
@@ -7969,6 +8596,8 @@ function buildProfileCompanySkill(paths, issueDefaults) {
7969
8596
  "1. Create a `company:research` issue with `type:company-profile`,",
7970
8597
  ` \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:research").status}\`. Body must include the`,
7971
8598
  " company name, selected type, framing, and any overrides.",
8599
+ "",
8600
+ ...renderIssueTypeAssignmentStep(),
7972
8601
  "2. Execute Phase 1 (Research) of the company-profile-analyst agent.",
7973
8602
  "3. Phase 1 creates the `company:draft` issue. Phase 2 may create a",
7974
8603
  " `company:followup` issue **and** a `company:match` issue. Each",
@@ -8043,6 +8672,8 @@ function buildMatchCompanySkill(paths, issueDefaults) {
8043
8672
  "1. Create a `company:match` issue with `type:company-profile`,",
8044
8673
  ` \`priority:${labelsForPhase(issueDefaults, "company:match").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:match").status}\`. Body must include the`,
8045
8674
  " profile path and any overrides.",
8675
+ "",
8676
+ ...renderIssueTypeAssignmentStep(),
8046
8677
  "2. Execute Phase 4 (Match) of the company-profile-analyst agent.",
8047
8678
  "",
8048
8679
  "## Output",
@@ -8116,6 +8747,8 @@ function buildRefreshCompanySkill(paths, issueDefaults) {
8116
8747
  "1. Create a `company:refresh` issue with `type:company-profile`,",
8117
8748
  ` \`priority:${labelsForPhase(issueDefaults, "company:refresh").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:refresh").status}\`. Body must include the`,
8118
8749
  " profile path and any overrides.",
8750
+ "",
8751
+ ...renderIssueTypeAssignmentStep(),
8119
8752
  "2. Execute Phase 5 (Refresh) of the company-profile-analyst agent.",
8120
8753
  "",
8121
8754
  "## Output",
@@ -8189,6 +8822,8 @@ function buildAnalyzeSegmentSkill(paths, issueDefaults) {
8189
8822
  "1. Create a `company:analyze` issue with `type:company-profile`,",
8190
8823
  ` \`priority:${labelsForPhase(issueDefaults, "company:analyze").priority}\`, and \`status:${labelsForPhase(issueDefaults, "company:analyze").status}\`. Body must include the`,
8191
8824
  " segment slug and any overrides.",
8825
+ "",
8826
+ ...renderIssueTypeAssignmentStep(),
8192
8827
  "2. Execute Phase 6 (Analyze) of the company-profile-analyst agent.",
8193
8828
  "",
8194
8829
  "## Output",
@@ -8777,6 +9412,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
8777
9412
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
8778
9413
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
8779
9414
  "",
9415
+ ...renderIssueTypeAssignmentStep(),
9416
+ "",
8780
9417
  "9. **Create `people:research` issues** for notable contacts",
8781
9418
  " (economic buyers, technical buyers, user champions) surfaced in",
8782
9419
  " sources. Keep the list small \u2014 at most three individuals per",
@@ -8788,6 +9425,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
8788
9425
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
8789
9426
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
8790
9427
  "",
9428
+ ...renderIssueTypeAssignmentStep(),
9429
+ "",
8791
9430
  "10. **Verify all handoffs were created** before committing.",
8792
9431
  "",
8793
9432
  "11. **Commit and push** the archetype page. Close the profile issue.",
@@ -8889,6 +9528,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
8889
9528
  ` - \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\``,
8890
9529
  ` - \`status:${labelsForPhase(issueDefaults, "req:scan").status}\``,
8891
9530
  "",
9531
+ ...renderIssueTypeAssignmentStep(),
9532
+ "",
8892
9533
  " The body must also:",
8893
9534
  " - Link back to the archetype page and the competitor page",
8894
9535
  " - Cite the specific unmet-need row and the originating job",
@@ -8905,6 +9546,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
8905
9546
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
8906
9547
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
8907
9548
  "",
9549
+ ...renderIssueTypeAssignmentStep(),
9550
+ "",
8908
9551
  "9. **Create `people:research` issues** for notable competitor",
8909
9552
  " leadership or customer-advocacy figures surfaced in the analysis.",
8910
9553
  " Keep this list small \u2014 at most three individuals per competitors",
@@ -8916,6 +9559,8 @@ function buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier) {
8916
9559
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
8917
9560
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
8918
9561
  "",
9562
+ ...renderIssueTypeAssignmentStep(),
9563
+ "",
8919
9564
  "10. **Commit and push** the competitor-analysis page and the",
8920
9565
  " updated archetype page. Close the competitors issue.",
8921
9566
  "",
@@ -9102,6 +9747,8 @@ function buildDiscoverCustomersSkill(paths, issueDefaults) {
9102
9747
  "1. Create a `customer:discover` issue with `type:customer-profile`,",
9103
9748
  ` \`priority:${labelsForPhase(issueDefaults, "customer:discover").priority}\`, and \`status:${labelsForPhase(issueDefaults, "customer:discover").status}\`. The body must include the`,
9104
9749
  " scope slug and any known archetypes to include or exclude.",
9750
+ "",
9751
+ ...renderIssueTypeAssignmentStep(),
9105
9752
  "2. Execute Phase 1 (Discover) of the customer-profile-analyst agent.",
9106
9753
  "3. Phase 1 writes the discovery report and creates one",
9107
9754
  " `customer:profile` issue per prioritized archetype.",
@@ -9177,6 +9824,8 @@ function buildProfileCustomerSkill(paths, issueDefaults) {
9177
9824
  "1. Create a `customer:profile` issue with `type:customer-profile`,",
9178
9825
  ` \`priority:${labelsForPhase(issueDefaults, "customer:profile").priority}\`, and \`status:${labelsForPhase(issueDefaults, "customer:profile").status}\`. The body must include the`,
9179
9826
  " archetype slug and (optionally) the segment slug.",
9827
+ "",
9828
+ ...renderIssueTypeAssignmentStep(),
9180
9829
  "2. Execute Phase 2 (Profile) of the customer-profile-analyst agent.",
9181
9830
  " The agent runs 4\u20138 targeted web searches and populates the",
9182
9831
  " archetype page.",
@@ -9253,6 +9902,8 @@ function buildAnalyzeCustomerCompetitorsSkill(paths, issueDefaults) {
9253
9902
  ` \`status:${labelsForPhase(issueDefaults, "customer:competitors").status}\` (or \`status:blocked\` when still dependent on a`,
9254
9903
  " Phase 2 profile issue). Body must include the archetype page",
9255
9904
  " path.",
9905
+ "",
9906
+ ...renderIssueTypeAssignmentStep(),
9256
9907
  "2. Execute Phase 3 (Competitors) of the customer-profile-analyst",
9257
9908
  " agent. The agent reads `<MATRIX_FILE>` and runs up to 4\u20138 web",
9258
9909
  " searches only to close competitor-coverage gaps the matrix does",
@@ -10962,10 +11613,7 @@ function buildGithubWorkflowBundle(buildPolicy = DEFAULT_BUILD_POLICY) {
10962
11613
  " - If unclear, ask the user which type applies",
10963
11614
  "2. **Compose the issue title** in the format: `<type>: <short description>`",
10964
11615
  "3. **Determine the GitHub issue type** based on the prefix:",
10965
- " - `epic:` \u2192 Epic",
10966
- " - `feat:` \u2192 Feature",
10967
- " - `fix:` \u2192 Bug",
10968
- " - `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` \u2192 Task",
11616
+ ...renderTitlePrefixTypeBullets(),
10969
11617
  "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
11618
  "5. **Determine labels** \u2014 every issue must be created with the following labels:",
10971
11619
  " - **`type:*`** \u2014 derived from the issue title prefix:",
@@ -11451,6 +12099,7 @@ function buildIndustryDiscoveryAnalystSubAgent(paths, issueDefaults) {
11451
12099
  " downstream research needs to answer)",
11452
12100
  " - Cite the evaluation row that justified advancing the vertical",
11453
12101
  " - Reference the plan file path for traceability",
12102
+ ...renderIssueTypeAssignmentStep({ indent: " ", bullet: true }),
11454
12103
  "",
11455
12104
  "5. **Cross-link** \u2014 update the plan file's `## Cleared Verticals`",
11456
12105
  " table so each row references its newly-created `research:scope`",
@@ -11541,6 +12190,8 @@ function buildDiscoverIndustriesSkill(paths, issueDefaults) {
11541
12190
  "1. Create an `industry:discover` issue with `type:industry-discovery`,",
11542
12191
  ` \`priority:${labelsForPhase(issueDefaults, "industry:discover").priority}\`, and \`status:${labelsForPhase(issueDefaults, "industry:discover").status}\`. Body must include the`,
11543
12192
  " verbatim scope, authorized sources, and any overrides.",
12193
+ "",
12194
+ ...renderIssueTypeAssignmentStep(),
11544
12195
  "2. Execute Phase 1 (Discover) of the industry-discovery-analyst",
11545
12196
  " agent.",
11546
12197
  "3. Phase 1 creates an `industry:evaluate` issue, which Phase 2 follows",
@@ -11819,6 +12470,8 @@ function buildMaintenanceAuditSubAgent(paths, tier) {
11819
12470
  "4. Commit, push, open a PR (if applicable), and close the issue per",
11820
12471
  " your project's PR workflow.",
11821
12472
  "",
12473
+ ...renderIssueTypeAssignmentBlanket(),
12474
+ "",
11822
12475
  "---",
11823
12476
  "",
11824
12477
  ...renderClaimVerificationSection(),
@@ -12251,6 +12904,8 @@ function buildMaintenanceAuditSkill(paths, issueDefaults) {
12251
12904
  " - `<AUDIT_ROOT>` \u2014 where to write the audit report",
12252
12905
  " - `<AUDIT_SLUG>` \u2014 short identifier for this audit",
12253
12906
  " - The audit checks to run (defaults to the full check catalog)",
12907
+ "",
12908
+ ...renderIssueTypeAssignmentStep(),
12254
12909
  "2. Execute Phase 1 (Scan) of the maintenance-audit agent.",
12255
12910
  "3. If auto-fixable findings exist, a `maint:fix` issue is created",
12256
12911
  " automatically.",
@@ -12315,6 +12970,8 @@ function buildMaintenanceVerifySkill(issueDefaults) {
12315
12970
  " - The Phase 2 fix report path (if one exists)",
12316
12971
  " - The `Paths Touched` list (copied from the fix report)",
12317
12972
  " - The audit check catalog (copied from the scan issue)",
12973
+ "",
12974
+ ...renderIssueTypeAssignmentStep(),
12318
12975
  "2. Execute Phase 3 (Verify) of the maintenance-audit agent.",
12319
12976
  "",
12320
12977
  "## Output",
@@ -12824,6 +13481,8 @@ function buildMeetingAnalystSubAgent(tier) {
12824
13481
  " - Always create a `meeting:link` issue \u2014 blocked on the draft issue if one",
12825
13482
  " was created, otherwise blocked on the notes issue",
12826
13483
  "",
13484
+ ...renderIssueTypeAssignmentStep(),
13485
+ "",
12827
13486
  "7. **Commit the extraction content first.** Stage and commit",
12828
13487
  " the `insights/{type}/<basename>.md` file (and any newly",
12829
13488
  " created `insights/index.md` / `insights/{type}/index.md`",
@@ -13023,6 +13682,8 @@ function buildMeetingAnalystSubAgent(tier) {
13023
13682
  "",
13024
13683
  "### Steps",
13025
13684
  "",
13685
+ ...renderIssueTypeAssignmentBlanket(),
13686
+ "",
13026
13687
  "1. Read the drafts from Phase 3 (if they exist) and the extraction",
13027
13688
  " from Phase 1 at `<meetingsRoot>/insights/{type}/<basename>.md`.",
13028
13689
  " Re-read the extraction frontmatter for `meeting_kind` and `areas`,",
@@ -13079,707 +13740,228 @@ function buildMeetingAnalystSubAgent(tier) {
13079
13740
  " (the degenerate case above). For the kind `planning`, also",
13080
13741
  " update the active sprint-plan doc directly (when the",
13081
13742
  " sprint-plan doc's area is in-scope, or always when no",
13082
- " `meetingAreas` are declared); for the kind `review`, mark",
13083
- " completed tasks in that same doc.",
13084
- "7. **Update the extraction file** at",
13085
- " `<meetingsRoot>/insights/{type}/<basename>.md` with a",
13086
- " `## Downstream Artifacts` section listing every issue and",
13087
- " document created from this meeting. Note any items that were",
13088
- " 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 };
13743
+ " `meetingAreas` are declared); for the kind `review`, mark",
13744
+ " completed tasks in that same doc.",
13745
+ "7. **Update the extraction file** at",
13746
+ " `<meetingsRoot>/insights/{type}/<basename>.md` with a",
13747
+ " `## Downstream Artifacts` section listing every issue and",
13748
+ " document created from this meeting. Note any items that were",
13749
+ " deferred to follow-up issues because of the area gate.",
13750
+ "8. **Update the meeting notes** at",
13751
+ " `<meetingsRoot>/notes/{type}/<basename>.md` with a",
13752
+ " `## Related Issues` section listing all issues created from this",
13753
+ " meeting.",
13754
+ "9. Comment on the parent extract issue with a summary linking to all",
13755
+ " created artifacts.",
13756
+ "10. Commit and push (if any file changes were made), then close the link issue.",
13757
+ "",
13758
+ "---",
13759
+ "",
13760
+ "## GitHub Integration",
13761
+ "",
13762
+ "- Use `gh` CLI for all GitHub operations",
13763
+ "- Apply the appropriate `meeting:*` phase label to each phase issue",
13764
+ "- Use `type:docs` for documentation-producing issues, `type:chore` for",
13765
+ " maintenance/organizational tasks the pipeline can action",
13766
+ "- Do **not** file issues for human-owned action items \u2014 per the",
13767
+ " **Action-item filing policy** they live only in the notes",
13768
+ " `## Action Items` table",
13769
+ "- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)",
13770
+ "- Reference the source meeting transcript in all created issues",
13771
+ "- Link phase issues with `Depends on: #N` to enforce ordering",
13772
+ "",
13773
+ "## When to Shorten the Pipeline",
13774
+ "",
13775
+ "- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session",
13776
+ "- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue",
13777
+ "- **Only action items**: extract + notes + link (3 phase issues)"
13778
+ ].join("\n")
13779
+ };
13499
13780
  }
13500
- function renderPhaseTypeInvariantSection(excludeBundles = []) {
13501
- const rows = Object.keys(PHASE_LABEL_TYPE_MAP).filter(
13502
- (matcher) => !isPhaseLabelMatcherOwnedByExcluded(matcher, excludeBundles)
13503
- ).sort().map((matcher) => {
13504
- const display = matcher.endsWith(":") ? `${matcher}*` : matcher;
13505
- const kind = matcher.endsWith(":") ? "prefix" : "exact";
13506
- return `| \`${display}\` | ${kind} | \`${PHASE_LABEL_TYPE_MAP[matcher]}\` |`;
13507
- });
13508
- return [
13509
- "## Phase-label \u2192 `type:<bundle>` invariant",
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.",
13781
+ var processMeetingSkill = {
13782
+ name: "process-meeting",
13783
+ description: "Process a meeting transcript through the 4-phase meeting analysis pipeline",
13784
+ disableModelInvocation: true,
13785
+ userInvocable: true,
13786
+ context: "fork",
13787
+ agent: "meeting-analyst",
13788
+ platforms: { cursor: { exclude: true } },
13789
+ instructions: [
13790
+ "# Process Meeting",
13525
13791
  "",
13526
- "| Phase label | Match | Required type label |",
13527
- "|-------------|-------|---------------------|",
13528
- ...rows,
13792
+ "Kick off meeting processing by executing Phase 1 (Extract) and",
13793
+ "creating downstream phase issues for the remaining phases. Inputs",
13794
+ "live in the **sibling-tree layout**: pass any file from",
13795
+ "`<meetingsRoot>/notes/{type}/` or `<meetingsRoot>/transcripts/{type}/`",
13796
+ "(both, notes-only, and transcript-only are all valid input cases).",
13529
13797
  "",
13530
- "### Enforcement",
13798
+ "## Usage",
13531
13799
  "",
13532
- "The Phase D maintenance sweep runs the invariant in auto-correct",
13533
- "mode and emits one summary line:",
13800
+ "/process-meeting <path-to-notes-or-transcript>",
13534
13801
  "",
13535
- "```",
13536
- "LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>",
13537
- "```",
13802
+ "## Basename-pairing algorithm",
13538
13803
  "",
13539
- "A **report-only** audit is available for repos that prefer",
13540
- "report-then-fix over auto-correct \u2014 same sweep, no mutations:",
13804
+ "The user may pass either a notes-tree path or a transcripts-tree",
13805
+ "path. Resolve the sibling implicitly via filesystem lookup \u2014",
13806
+ "do **not** prompt the user or fail-loud when the sibling is",
13807
+ "absent:",
13541
13808
  "",
13542
- "```bash",
13543
- ".claude/procedures/check-blocked.sh label-invariant # report only",
13544
- ".claude/procedures/check-blocked.sh label-invariant --fix # apply",
13545
- "```",
13809
+ "1. Infer the **basename** (filename without the `.md` extension)",
13810
+ " and the `{internal,external}` partition from the provided path.",
13811
+ " Both segments are usually adjacent in the path \u2014",
13812
+ " `\u2026/notes/internal/2026-03-14-sprint-kickoff.md` yields basename",
13813
+ " `2026-03-14-sprint-kickoff` and type `internal`.",
13814
+ "2. Determine the **input tree** from the path:",
13815
+ " - If the path contains `/notes/`, treat it as the notes input",
13816
+ " and look for the sibling at",
13817
+ " `<meetingsRoot>/transcripts/<type>/<basename>.md`.",
13818
+ " - If the path contains `/transcripts/`, treat it as the",
13819
+ " transcript input and look for the sibling at",
13820
+ " `<meetingsRoot>/notes/<type>/<basename>.md`.",
13821
+ " - If the path matches neither (e.g. an ad-hoc location), infer",
13822
+ " basename + type as best you can from the filename and",
13823
+ " surrounding folder segments, then proceed with whichever",
13824
+ " sibling-tree lookups succeed. Best-effort, never fail-loud.",
13825
+ "3. Read **every** sibling that exists on disk. The combination",
13826
+ " (notes present, transcript present, both present) selects the",
13827
+ " Phase-1 input case from the **input-case matrix** in the",
13828
+ " `meeting-analyst` agent prompt.",
13829
+ "4. A missing sibling is a normal outcome \u2014 proceed with whatever",
13830
+ " was found. Notes-only and transcript-only are both valid",
13831
+ " Phase-1 input cases; the agent never warns or prompts the",
13832
+ " user about the absence.",
13546
13833
  "",
13547
- "### Correction policy",
13834
+ "## Steps",
13548
13835
  "",
13549
- "An issue must carry **exactly one** `type:*` label. Merely *adding*",
13550
- "the required type label to an issue that already carries a",
13551
- "conventional-commit one would leave two, making the funnel-tier sort",
13552
- "key (which reads the **first** `type:*` label) non-deterministic and",
13553
- "violating the label conventions. The correction therefore",
13554
- "**replaces**, in a single atomic `gh issue edit`, so the issue is",
13555
- "never observable carrying two `type:*` labels:",
13836
+ "1. Resolve the basename, partition, and any sibling files using",
13837
+ " the **Basename-pairing algorithm** above",
13838
+ "2. Execute Phase 1 (Extract) \u2014 categorize the available content into",
13839
+ " decisions, requirements, action items, open questions, and more.",
13840
+ " Tag each action item's disposition (`agent-workable` vs",
13841
+ " `human-owned`) per the agent's **Action-item filing policy** so",
13842
+ " Phase 4 keeps human-owned tasks out of the issue queue",
13843
+ "3. Write the extraction to",
13844
+ " `<meetingsRoot>/insights/{type}/<basename>.md`",
13845
+ "4. Create downstream phase issues using `gh issue create`:",
13846
+ " - `meeting:notes` issue (always)",
13847
+ " - `meeting:draft` issue (if requirements or decisions were found)",
13848
+ " - `meeting:link` issue (always)",
13556
13849
  "",
13557
- "| Issue state | Action |",
13558
- "|-------------|--------|",
13559
- "| Required type label present, nothing else | none \u2014 compliant, left untouched |",
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 |",
13850
+ ...renderIssueTypeAssignmentStep(),
13851
+ "5. Each downstream issue includes `Depends on:` linking to its predecessor",
13852
+ "6. Commit and push the extraction file",
13565
13853
  "",
13566
- "Only a conventional-commit `type:*` label is ever removed. A",
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.",
13854
+ "## Input",
13573
13855
  "",
13574
- "`status:needs-attention` is applied **additively** \u2014 the base",
13575
- "`status:*` label always stays, per the additive-flag rule. Flagging",
13576
- "is idempotent: an issue already carrying the flag is reported but",
13577
- "not re-flagged."
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
- "}",
13856
+ "Provide a path to a file in either `notes/` or `transcripts/`. The",
13857
+ "agent will look up the sibling automatically via basename match. A",
13858
+ "missing sibling is a normal case (notes-only or transcript-only) \u2014",
13859
+ "the agent handles all three input cases.",
13620
13860
  "",
13621
- "# Return 0 when the argument is a conventional-commit `type:*`",
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
- "}",
13861
+ "## Output",
13631
13862
  "",
13632
- "# Resolve an issue's FULL label list (one label per line on stdin)",
13633
- "# to the type label the phase-label invariant requires. Emits",
13634
- "# KEY=VALUE assignments the caller parses:",
13635
- "# OUTCOME=none \u2014 no recognised phase label; invariant N/A",
13636
- "# OUTCOME=match \u2014 plus TYPE_LABEL=<type:bundle>",
13637
- "# OUTCOME=ambiguous \u2014 plus CANDIDATE_TYPE_LABELS=<space-separated>",
13638
- "# PHASE_LABELS=<space-separated recognised phase labels>",
13639
- "phase_type_of() {",
13640
- " local label resolved",
13641
- ' local matched_types=""',
13642
- ' local matched_phase=""',
13643
- " while IFS= read -r label; do",
13644
- ' [ -z "$label" ] && continue',
13645
- ' resolved=$(phase_label_type_of "$label")',
13646
- ' [ -z "$resolved" ] && continue',
13647
- ' matched_phase="${matched_phase}${label} "',
13648
- ' case " ${matched_types} " in',
13649
- ' *" ${resolved} "*) ;;',
13650
- ' *) matched_types="${matched_types}${resolved} " ;;',
13651
- " esac",
13652
- " done",
13653
- " local count=0",
13654
- " for resolved in $matched_types; do",
13655
- " count=$((count + 1))",
13656
- " done",
13657
- ' if [ "$count" -eq 0 ]; then',
13658
- ' echo "OUTCOME=none"',
13659
- ' elif [ "$count" -eq 1 ]; then',
13660
- ' echo "OUTCOME=match"',
13661
- ' echo "TYPE_LABEL=${matched_types% }"',
13662
- " else",
13663
- ' echo "OUTCOME=ambiguous"',
13664
- ' echo "CANDIDATE_TYPE_LABELS=${matched_types% }"',
13665
- " fi",
13666
- ' echo "PHASE_LABELS=${matched_phase% }"',
13667
- "}"
13668
- );
13669
- return lines.join("\n");
13670
- }
13671
- function buildPhaseLabelTypeMap() {
13672
- const map = {};
13673
- for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {
13674
- if (ownership.phaseLabelPrefixes.length === 0) {
13675
- continue;
13676
- }
13677
- if (ownership.typeLabels.length !== 1) {
13678
- throw new Error(
13679
- `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`
13680
- );
13681
- }
13682
- const typeLabel = `type:${ownership.typeLabels[0]}`;
13683
- for (const matcher of ownership.phaseLabelPrefixes) {
13684
- const existing = map[matcher];
13685
- if (existing !== void 0 && existing !== typeLabel) {
13686
- throw new Error(
13687
- `Phase-label matcher "${matcher}" resolves to both "${existing}" and "${typeLabel}"; a matcher must imply exactly one type label`
13688
- );
13689
- }
13690
- map[matcher] = typeLabel;
13691
- }
13692
- }
13693
- return map;
13694
- }
13695
- function isTypeLabelOwnedByExcluded(typeLabel, excludedBundles) {
13696
- if (excludedBundles.length === 0) {
13697
- return false;
13698
- }
13699
- for (const bundleName of excludedBundles) {
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;
13863
+ "- A structured extraction at",
13864
+ " `<meetingsRoot>/insights/{type}/<basename>.md`",
13865
+ "- Phase issues with `meeting:*` labels for downstream agent sessions",
13866
+ " to pick up (notes, draft, link)"
13867
+ ].join("\n")
13868
+ };
13869
+ function buildMeetingAnalysisBundle(tier = AGENT_MODEL.BALANCED) {
13870
+ return {
13871
+ name: "meeting-analysis",
13872
+ description: "Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)",
13873
+ appliesWhen: () => true,
13874
+ rules: [
13875
+ {
13876
+ name: "meeting-processing-workflow",
13877
+ description: "Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions",
13878
+ scope: AGENT_RULE_SCOPE.ALWAYS,
13879
+ content: [
13880
+ "# Meeting Processing Workflow",
13881
+ "",
13882
+ "Use `/process-meeting <path>` to process a meeting through a",
13883
+ "4-phase pipeline (extract \u2192 notes \u2192 draft \u2192 link). Each phase runs as a",
13884
+ "separate agent session tracked by a GitHub issue with a `meeting:*` label.",
13885
+ "See the `meeting-analyst` agent definition for full workflow details.",
13886
+ "",
13887
+ "Meeting artifacts live in **three parallel trees** rooted at the",
13888
+ "project's meetings root:",
13889
+ "",
13890
+ "- `transcripts/{internal,external}/` \u2014 verbatim transcripts (evidence)",
13891
+ "- `notes/{internal,external}/` \u2014 curated narrative summary",
13892
+ " (input + Phase 2 output)",
13893
+ "- `insights/{internal,external}/` \u2014 structured extraction (Phase 1 output)",
13894
+ "",
13895
+ "The three trees share identical basenames so a meeting's siblings",
13896
+ "are looked up by filename, not by frontmatter cross-references.",
13897
+ "Phase 1 accepts every input case (notes + transcript, notes only,",
13898
+ "or transcript only) and Phase 2 enhances the notes file in place",
13899
+ "rather than authoring it from scratch.",
13900
+ "",
13901
+ "Notes and insights files may carry optional frontmatter fields",
13902
+ "`slug`, `source`, `transcript_available`, and `confidence`",
13903
+ "alongside the existing `meeting_type` and `areas` fields. Missing",
13904
+ "frontmatter is treated as a normal input case \u2014 never fail-loud.",
13905
+ "",
13906
+ "Meeting notes may declare a `meeting_type` (one of the project's",
13907
+ "recognized types) and an `areas: [...]` list. The `meeting_type`",
13908
+ "resolves to a generic kind \u2014 `planning` / `review` / `brainstorm` /",
13909
+ "`standup` / `external` / `other` \u2014 that drives type-specific",
13910
+ "extraction rules in phases 1\u20132. The `areas` list scopes phase-4",
13911
+ "direct edits to the doc-root sub-folders declared in the project's",
13912
+ "**Area \u2192 doc-root mapping** table. When both fields are absent",
13913
+ "the pipeline falls back to the default workflow (kind `other`,",
13914
+ "no area gating).",
13915
+ "",
13916
+ "Phase 4 applies an **agent-workability split** to action items:",
13917
+ "items that yield a documentation deliverable an agent can author",
13918
+ "are filed through their dedicated downstream channel",
13919
+ "(`req:write`, `docs:write`, `bcm:*`, `research:scope`, roadmap",
13920
+ "follow-up); human-owned tasks (send / schedule / install /",
13921
+ "decide / communicate / get-access / build-elsewhere) are",
13922
+ "recorded **only** in the notes `## Action Items` table, which is",
13923
+ "the **system of record for human follow-ups** \u2014 no GitHub issue",
13924
+ "is filed for them. Consumers tune or disable the split via",
13925
+ "`AgentConfigOptions.meetings.actionItemFiling`."
13926
+ ].join("\n"),
13927
+ platforms: {
13928
+ cursor: { exclude: true }
13929
+ },
13930
+ tags: ["workflow"]
13711
13931
  }
13712
- }
13713
- }
13714
- return false;
13715
- }
13716
- function isPhaseLabelOwnedByExcluded(phaseLabel, excludedBundles) {
13717
- if (excludedBundles.length === 0) {
13718
- return false;
13719
- }
13720
- for (const bundleName of excludedBundles) {
13721
- const ownership = BUNDLE_OWNERSHIP[bundleName];
13722
- if (!ownership) {
13723
- continue;
13724
- }
13725
- for (const entry of ownership.phaseLabelPrefixes) {
13726
- if (entry.endsWith(":")) {
13727
- if (phaseLabel.startsWith(entry)) {
13728
- return true;
13729
- }
13730
- } else if (phaseLabel === entry) {
13731
- return true;
13932
+ ],
13933
+ skills: [processMeetingSkill],
13934
+ subAgents: [buildMeetingAnalystSubAgent(tier)],
13935
+ labels: [
13936
+ {
13937
+ name: "type:meeting-processing",
13938
+ color: "5319E7",
13939
+ description: "Meeting transcript processing pipeline"
13940
+ },
13941
+ {
13942
+ name: "meeting:extract",
13943
+ color: "C5DEF5",
13944
+ description: "Phase 1: raw extraction from a meeting transcript"
13945
+ },
13946
+ {
13947
+ name: "meeting:notes",
13948
+ color: "BFDADC",
13949
+ description: "Phase 2: curated notes derived from an extraction"
13950
+ },
13951
+ {
13952
+ name: "meeting:draft",
13953
+ color: "D4C5F9",
13954
+ description: "Phase 3: draft follow-up issues proposed from notes"
13955
+ },
13956
+ {
13957
+ name: "meeting:link",
13958
+ color: "FEF2C0",
13959
+ description: "Phase 4: linking/reconciling drafted issues with existing work"
13732
13960
  }
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;
13961
+ ]
13962
+ };
13782
13963
  }
13964
+ var meetingAnalysisBundle = buildMeetingAnalysisBundle();
13783
13965
 
13784
13966
  // src/agent/bundles/run-ratio.ts
13785
13967
  var DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO = 4;
@@ -19416,6 +19598,8 @@ function buildPeopleProfileAnalystSubAgent(paths, issueDefaults, tier) {
19416
19598
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
19417
19599
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
19418
19600
  "",
19601
+ ...renderIssueTypeAssignmentStep(),
19602
+ "",
19419
19603
  " The issue body must include:",
19420
19604
  " - A **discovery source** line naming this person profile",
19421
19605
  " (`Discovered while profiling: <person name>`)",
@@ -19436,6 +19620,8 @@ function buildPeopleProfileAnalystSubAgent(paths, issueDefaults, tier) {
19436
19620
  ` - \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\``,
19437
19621
  ` - \`status:${labelsForPhase(issueDefaults, "software:research").status}\``,
19438
19622
  "",
19623
+ ...renderIssueTypeAssignmentStep(),
19624
+ "",
19439
19625
  " The issue body must include:",
19440
19626
  " - A **discovery source** line naming this person profile",
19441
19627
  " (`Discovered while profiling: <person name>`)",
@@ -19718,6 +19904,8 @@ function buildProfilePersonSkill(paths, issueDefaults) {
19718
19904
  ` \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "people:research").status}\`. Body must include the`,
19719
19905
  " person's name, selected role, primary company, framing, and any",
19720
19906
  " overrides.",
19907
+ "",
19908
+ ...renderIssueTypeAssignmentStep(),
19721
19909
  "2. Execute Phase 1 (Research) of the people-profile-analyst agent.",
19722
19910
  "3. Phase 1 creates the `people:draft` issue. Phase 2 may create a",
19723
19911
  " `people:followup` issue. Each downstream issue declares its",
@@ -19809,6 +19997,8 @@ function buildRefreshPersonSkill(paths, issueDefaults) {
19809
19997
  "1. Create a `people:refresh` issue with `type:people-profile`,",
19810
19998
  ` \`priority:${labelsForPhase(issueDefaults, "people:refresh").priority}\`, and \`status:${labelsForPhase(issueDefaults, "people:refresh").status}\`. Body must include the`,
19811
19999
  " profile path and any overrides.",
20000
+ "",
20001
+ ...renderIssueTypeAssignmentStep(),
19812
20002
  "2. Execute Phase 4 (Refresh) of the people-profile-analyst agent.",
19813
20003
  "",
19814
20004
  "## Output",
@@ -23505,6 +23695,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
23505
23695
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
23506
23696
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
23507
23697
  "",
23698
+ ...renderIssueTypeAssignmentStep(),
23699
+ "",
23508
23700
  "9. **Verify all handoffs were created** before committing.",
23509
23701
  "",
23510
23702
  "10. **Commit and push** the regulation page. Close the research",
@@ -23615,6 +23807,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
23615
23807
  ` - \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\``,
23616
23808
  ` - \`status:${labelsForPhase(issueDefaults, "req:scan").status}\``,
23617
23809
  "",
23810
+ ...renderIssueTypeAssignmentStep(),
23811
+ "",
23618
23812
  " The body must also:",
23619
23813
  " - Identify the target category as **SEC** (security & compliance)",
23620
23814
  " in the body so the downstream writer phase picks up the right",
@@ -23634,6 +23828,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
23634
23828
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
23635
23829
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
23636
23830
  "",
23831
+ ...renderIssueTypeAssignmentStep(),
23832
+ "",
23637
23833
  "6. **Create `people:research` issues** for notable regulatory",
23638
23834
  " leaders (commissioners, agency directors, lead policy authors)",
23639
23835
  " mentioned on the regulation page. Keep this list small \u2014 at most",
@@ -23645,6 +23841,8 @@ function buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults) {
23645
23841
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
23646
23842
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
23647
23843
  "",
23844
+ ...renderIssueTypeAssignmentStep(),
23845
+ "",
23648
23846
  "7. **Commit and push** the updated regulation page. Close the",
23649
23847
  " impact issue.",
23650
23848
  "",
@@ -23812,6 +24010,8 @@ function buildScanRegulatoryLandscapeSkill(paths, issueDefaults) {
23812
24010
  ` \`priority:${labelsForPhase(issueDefaults, "regulatory:scan").priority}\`, and \`status:${labelsForPhase(issueDefaults, "regulatory:scan").status}\`. The body must include the`,
23813
24011
  " scope slug, the scope type, and any known regulations to include",
23814
24012
  " or exclude.",
24013
+ "",
24014
+ ...renderIssueTypeAssignmentStep(),
23815
24015
  "2. Execute Phase 1 (Scan) of the regulatory-research-analyst agent.",
23816
24016
  "3. Phase 1 writes the scan report and creates one",
23817
24017
  " `regulatory:research` issue per prioritized regulation.",
@@ -23888,6 +24088,8 @@ function buildResearchRegulationSkill(paths, issueDefaults) {
23888
24088
  ` \`type:regulatory-research\`, \`priority:${labelsForPhase(issueDefaults, "regulatory:research").priority}\`, and`,
23889
24089
  ` \`status:${labelsForPhase(issueDefaults, "regulatory:research").status}\`. The body must include the scope slug and the`,
23890
24090
  " regulation slug.",
24091
+ "",
24092
+ ...renderIssueTypeAssignmentStep(),
23891
24093
  "2. Execute Phase 2 (Research) of the regulatory-research-analyst",
23892
24094
  " agent. The agent runs 6\u201312 targeted web searches and populates",
23893
24095
  " the regulation page.",
@@ -23955,6 +24157,8 @@ function buildImpactRegulationSkill(paths, issueDefaults) {
23955
24157
  ` \`status:${labelsForPhase(issueDefaults, "regulatory:impact").status}\` (or \`status:blocked\` when still dependent on a`,
23956
24158
  " Phase 2 research issue). Body must include the regulation page",
23957
24159
  " path.",
24160
+ "",
24161
+ ...renderIssueTypeAssignmentStep(),
23958
24162
  "2. Execute Phase 3 (Impact) of the regulatory-research-analyst",
23959
24163
  " agent. No web searches \u2014 pure synthesis from the regulation",
23960
24164
  " page and project context.",
@@ -26790,6 +26994,8 @@ function buildWriteRequirementSkill(paths, issueDefaults) {
26790
26994
  " Body must include the category, tier, output path, and a pointer",
26791
26995
  " to the upstream proposal (or a direct user description if no",
26792
26996
  " proposals file exists).",
26997
+ "",
26998
+ ...renderIssueTypeAssignmentStep(),
26793
26999
  "2. Execute the write phase of the requirements-writer agent.",
26794
27000
  "3. The agent writes one requirement document, updates the category",
26795
27001
  " index, opens a PR, and closes the issue.",
@@ -27379,6 +27585,8 @@ function buildRequirementsAnalystSubAgent(paths, issueDefaults) {
27379
27585
  ` \`--label "tier:<tier-slug>"\`, \`--label "status:${labelsForPhase(issueDefaults, "req:write").status}"\`, and`,
27380
27586
  ` \`--label "priority:${labelsForPhase(issueDefaults, "req:write").priority}"\`.`,
27381
27587
  "",
27588
+ ...renderIssueTypeAssignmentStep(),
27589
+ "",
27382
27590
  " The body must carry the three writer-required fields in an",
27383
27591
  " `## Objective` block, written as bold-prefixed lines so the",
27384
27592
  " writer's intake parser can pull them out, plus the reserved-ID",
@@ -27525,6 +27733,8 @@ function buildScanRequirementsSkill(issueDefaults) {
27525
27733
  "",
27526
27734
  `1. Create a \`req:scan\` issue with \`type:requirement\`, \`priority:${labelsForPhase(issueDefaults, "req:scan").priority}\`,`,
27527
27735
  ` and \`status:${labelsForPhase(issueDefaults, "req:scan").status}\`. Body must list the files to read and the scan scope.`,
27736
+ "",
27737
+ ...renderIssueTypeAssignmentStep(),
27528
27738
  "2. Execute Phase 1 (Scan) of the requirements-analyst agent.",
27529
27739
  "3. If gaps are found, a `req:draft-trace` issue is created automatically.",
27530
27740
  "",
@@ -28573,6 +28783,7 @@ function buildRequirementsReviewerSubAgent(paths, issueDefaults) {
28573
28783
  "- Labels: `type:requirement`, `req:write`, the matching",
28574
28784
  " `tier:*` label derived from the referencing document's Tier,",
28575
28785
  ` \`priority:${labelsForPhase(issueDefaults, "req:write").priority}\`, \`status:${labelsForPhase(issueDefaults, "req:write").status}\`.`,
28786
+ ...renderIssueTypeAssignmentStep({ indent: "", bullet: true }),
28576
28787
  "- If any of Category / Tier / Output Path cannot be derived from",
28577
28788
  " the referencing document, open the follow-up with",
28578
28789
  " `status:needs-attention` and a `Missing:` line, per the same",
@@ -28728,6 +28939,8 @@ function buildReviewRequirementsSkill(paths, issueDefaults) {
28728
28939
  ` \`priority:${labelsForPhase(issueDefaults, "req:review").priority}\`, and \`status:${labelsForPhase(issueDefaults, "req:review").status}\`. Body must include the`,
28729
28940
  " scope, the requirements root (or accept the default), and the",
28730
28941
  " output path.",
28942
+ "",
28943
+ ...renderIssueTypeAssignmentStep(),
28731
28944
  "2. Execute the review phase of the requirements-reviewer agent.",
28732
28945
  "3. The agent runs the 12-check audit, writes a structured report",
28733
28946
  " grouped by Critical / Warning / Info (plus a separate",
@@ -28830,6 +29043,8 @@ function buildDeprecateRequirementSkill(_paths, issueDefaults) {
28830
29043
  ` \`priority:${labelsForPhase(issueDefaults, "req:deprecate").priority}\`, and \`status:${labelsForPhase(issueDefaults, "req:deprecate").status}\`. Body must include the`,
28831
29044
  " Targets, Transition, and Reason sections above (optionally",
28832
29045
  " `Pre-approved: yes`).",
29046
+ "",
29047
+ ...renderIssueTypeAssignmentStep(),
28833
29048
  "2. Execute the deprecation phase of the requirements-reviewer",
28834
29049
  " agent.",
28835
29050
  "3. The agent verifies inputs, pauses for human confirmation (or",
@@ -29404,6 +29619,8 @@ function buildResearchSkill(paths, issueDefaults) {
29404
29619
  "1. Create a `research:scope` issue with `type:research`,",
29405
29620
  ` \`priority:${labelsForPhase(issueDefaults, "research:scope").priority}\`, and \`status:${labelsForPhase(issueDefaults, "research:scope").status}\`. Body must include the`,
29406
29621
  " verbatim question, authorized sources, and any overrides.",
29622
+ "",
29623
+ ...renderIssueTypeAssignmentStep(),
29407
29624
  "2. Execute Phase 1 (Scope) of the research-analyst agent.",
29408
29625
  "3. Phase 1 creates `research:slice` issues (one per slice) and a",
29409
29626
  " single `research:verify` issue. Each downstream issue declares",
@@ -30219,6 +30436,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
30219
30436
  ` - \`priority:${labelsForPhase(issueDefaults, "bcm:outline").priority}\``,
30220
30437
  ` - \`status:${labelsForPhase(issueDefaults, "bcm:outline").status}\``,
30221
30438
  "",
30439
+ ...renderIssueTypeAssignmentStep(),
30440
+ "",
30222
30441
  " The issue body must include:",
30223
30442
  " - A **discovery source** line naming this software profile",
30224
30443
  " (`Discovered while mapping: <product name>`)",
@@ -30287,6 +30506,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
30287
30506
  " `software:research` phase with `type:software-profile`,",
30288
30507
  ` \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:research").status}\`.`,
30289
30508
  "",
30509
+ ...renderIssueTypeAssignmentStep(),
30510
+ "",
30290
30511
  "3. **Enqueue a `company:research` issue for the vendor company** if",
30291
30512
  " no matching profile already exists under `<COMPANY_PROFILES_DIR>/`.",
30292
30513
  " The vendor (the company that builds or maintains the product)",
@@ -30299,6 +30520,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
30299
30520
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
30300
30521
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
30301
30522
  "",
30523
+ ...renderIssueTypeAssignmentStep(),
30524
+ "",
30302
30525
  " The issue body must include:",
30303
30526
  " - A **discovery source** line naming this software profile",
30304
30527
  " (`Discovered while profiling: <product name>`)",
@@ -30318,6 +30541,8 @@ function buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier) {
30318
30541
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
30319
30542
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
30320
30543
  "",
30544
+ ...renderIssueTypeAssignmentStep(),
30545
+ "",
30321
30546
  " The issue body must include:",
30322
30547
  " - A **discovery source** line naming this software profile",
30323
30548
  " (`Discovered while profiling: <product name>`)",
@@ -30508,6 +30733,8 @@ function buildProfileSoftwareSkill(paths, issueDefaults) {
30508
30733
  "1. Create a `software:research` issue with `type:software-profile`,",
30509
30734
  ` \`priority:${labelsForPhase(issueDefaults, "software:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:research").status}\`. Body must include the`,
30510
30735
  " product name, selected type, framing, and any overrides.",
30736
+ "",
30737
+ ...renderIssueTypeAssignmentStep(),
30511
30738
  "2. Execute Phase 1 (Research) of the software-profile-analyst",
30512
30739
  " agent.",
30513
30740
  "3. Phase 1 creates the `software:profile` issue. Phase 2 creates",
@@ -30596,6 +30823,8 @@ function buildMapSoftwareSkill(paths, issueDefaults) {
30596
30823
  "1. Create a `software:map` issue with `type:software-profile`,",
30597
30824
  ` \`priority:${labelsForPhase(issueDefaults, "software:map").priority}\`, and \`status:${labelsForPhase(issueDefaults, "software:map").status}\`. Body must include the`,
30598
30825
  " profile path and any overrides.",
30826
+ "",
30827
+ ...renderIssueTypeAssignmentStep(),
30599
30828
  "2. Execute Phase 4 (Map) of the software-profile-analyst agent.",
30600
30829
  "3. Phase 4 writes the `## Capability Mapping` section, enqueues",
30601
30830
  " `bcm:outline` issues for unmapped features above the threshold,",
@@ -31208,6 +31437,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
31208
31437
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
31209
31438
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
31210
31439
  "",
31440
+ ...renderIssueTypeAssignmentStep(),
31441
+ "",
31211
31442
  "6. **Create `people:research` issues** for every entry in *People of",
31212
31443
  " Interest* that does not already have a canonical person profile",
31213
31444
  " or an open `people:research` issue. The `people-profile` bundle",
@@ -31219,6 +31450,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
31219
31450
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
31220
31451
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
31221
31452
  "",
31453
+ ...renderIssueTypeAssignmentStep(),
31454
+ "",
31222
31455
  "7. **Verify all handoffs were created** before committing. For each",
31223
31456
  " entity in both tables, confirm an existing profile or a fresh",
31224
31457
  " handoff issue exists. Do not commit with missing handoffs.",
@@ -31512,6 +31745,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
31512
31745
  ` - \`priority:${labelsForPhase(issueDefaults, "company:research").priority}\``,
31513
31746
  ` - \`status:${labelsForPhase(issueDefaults, "company:research").status}\``,
31514
31747
  "",
31748
+ ...renderIssueTypeAssignmentStep(),
31749
+ "",
31515
31750
  "6. **Hand off canonical people profiles** by creating one",
31516
31751
  " `people:research` issue per leadership entry that does not",
31517
31752
  " already have a canonical profile or an open `people:research`",
@@ -31523,6 +31758,8 @@ function buildStandardsResearchAnalystSubAgent(paths, issueDefaults) {
31523
31758
  ` - \`priority:${labelsForPhase(issueDefaults, "people:research").priority}\``,
31524
31759
  ` - \`status:${labelsForPhase(issueDefaults, "people:research").status}\``,
31525
31760
  "",
31761
+ ...renderIssueTypeAssignmentStep(),
31762
+ "",
31526
31763
  "7. **Commit and push** the organization page. Close the",
31527
31764
  " organizations issue.",
31528
31765
  "",
@@ -31697,6 +31934,8 @@ function buildScopeStandardsResearchSkill(paths, issueDefaults) {
31697
31934
  ` \`priority:${labelsForPhase(issueDefaults, "standards:scope").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:scope").status}\`. The body must include the`,
31698
31935
  " standard slug, the list of target versions (or a request to",
31699
31936
  " enumerate), and any known governance bodies.",
31937
+ "",
31938
+ ...renderIssueTypeAssignmentStep(),
31700
31939
  "2. Execute Phase 1 (Scope) of the standards-research-analyst agent.",
31701
31940
  "3. Phase 1 writes the query plan and creates one `standards:research`",
31702
31941
  " issue per target version, one `standards:compare` issue (blocked",
@@ -31761,6 +32000,8 @@ function buildResearchStandardSkill(paths, issueDefaults) {
31761
32000
  "1. Create a `standards:research` issue with",
31762
32001
  ` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:research").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:research").status}\`.`,
31763
32002
  " The body must include the standard slug and the version slug.",
32003
+ "",
32004
+ ...renderIssueTypeAssignmentStep(),
31764
32005
  "2. Execute Phase 2 (Research) of the standards-research-analyst",
31765
32006
  " agent. The agent runs 6\u201310 targeted web searches and populates",
31766
32007
  " the version page.",
@@ -31834,6 +32075,8 @@ function buildCompareStandardsSkill(paths, issueDefaults) {
31834
32075
  ` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:compare").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:compare").status}\`.`,
31835
32076
  " Body must include the standard slug and the list of version",
31836
32077
  " pages under comparison.",
32078
+ "",
32079
+ ...renderIssueTypeAssignmentStep(),
31837
32080
  "2. Execute Phase 3 (Compare) of the standards-research-analyst",
31838
32081
  " agent. No web searches \u2014 pure synthesis from the version pages.",
31839
32082
  "",
@@ -31902,6 +32145,8 @@ function buildExtensionStandardSkill(paths, issueDefaults) {
31902
32145
  " The body must include the standard slug, the entity slug, the",
31903
32146
  " closest resource, and a link to the source BCM or canvas",
31904
32147
  " document.",
32148
+ "",
32149
+ ...renderIssueTypeAssignmentStep(),
31905
32150
  "2. Execute Phase 4 (Extension) of the standards-research-analyst",
31906
32151
  " agent. The agent runs 4\u20138 targeted web searches against",
31907
32152
  " community registries, implementation guides, and working-group",
@@ -31967,6 +32212,8 @@ function buildOrganizationsStandardSkill(paths, issueDefaults) {
31967
32212
  ` \`type:standards-research\`, \`priority:${labelsForPhase(issueDefaults, "standards:organizations").priority}\`, and \`status:${labelsForPhase(issueDefaults, "standards:organizations").status}\`.`,
31968
32213
  " Body must include the standard slug, the organization slug, and",
31969
32214
  " the organization's governance role.",
32215
+ "",
32216
+ ...renderIssueTypeAssignmentStep(),
31970
32217
  "2. Execute Phase 5 (Organizations) of the",
31971
32218
  " standards-research-analyst agent. The agent runs 4\u20138 targeted",
31972
32219
  " web searches.",
@@ -32276,6 +32523,14 @@ var UPSTREAM_CONFIGULATOR_DOCS_SUMMARY = [
32276
32523
  "",
32277
32524
  "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
32525
  "",
32526
+ "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:",
32527
+ "",
32528
+ "```sh",
32529
+ "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",
32530
+ "gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'",
32531
+ "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>",
32532
+ "```",
32533
+ "",
32279
32534
  "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
32535
  ].join("\n");
32281
32536
  var UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [
@@ -32384,6 +32639,16 @@ var UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [
32384
32639
  "- `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
32640
  "- `status:*` \u2014 `status:ready` for self-contained issues, `status:blocked` when the issue declares `Depends on: #<n>` against another open issue.",
32386
32641
  "",
32642
+ "### GitHub issue type",
32643
+ "",
32644
+ "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:",
32645
+ "",
32646
+ "```sh",
32647
+ "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",
32648
+ "gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'",
32649
+ "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>",
32650
+ "```",
32651
+ "",
32387
32652
  "### Worked example",
32388
32653
  "",
32389
32654
  "Suppose configulator's `software-profile-analyst` agent prompt is missing a step you need. Instead of forking the prompt locally:",
@@ -41195,6 +41460,7 @@ export {
41195
41460
  DEFAULT_DECOMPOSITION_TEMPLATE,
41196
41461
  DEFAULT_DISPATCH_MODEL,
41197
41462
  DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO,
41463
+ DEFAULT_GITHUB_ISSUE_TYPE,
41198
41464
  DEFAULT_HOUSEKEEPING_MODEL,
41199
41465
  DEFAULT_ISSUE_PRIORITY,
41200
41466
  DEFAULT_ISSUE_STATUS,
@@ -41241,6 +41507,8 @@ export {
41241
41507
  DEFAULT_UNBLOCK_DEPENDENTS_ENABLED,
41242
41508
  DEFAULT_UPSTREAM_CONFIGULATOR_ENABLED,
41243
41509
  DOCS_SYNC_AUDIT_SCHEMA_VERSION,
41510
+ GITHUB_ISSUE_TYPES,
41511
+ GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX,
41244
41512
  JsiiFaker,
41245
41513
  LAYOUT_ENFORCEMENT,
41246
41514
  LAYOUT_ROOT_BY_PROJECT_TYPE,
@@ -41265,6 +41533,7 @@ export {
41265
41533
  ResetTask,
41266
41534
  SCHEDULED_TASK_MODEL_VALUES,
41267
41535
  SCOPE_CLASS_VALUES,
41536
+ SET_ISSUE_TYPE_HELPER_PATH,
41268
41537
  SHARED_EDITING_CONFLICT_STRATEGY_VALUES,
41269
41538
  STARLIGHT_ROLE,
41270
41539
  SUPPRESSED_WORKFLOW_RULE_NAMES,
@@ -41350,6 +41619,7 @@ export {
41350
41619
  formatLayoutViolation,
41351
41620
  formatStarlightSingletonViolation,
41352
41621
  getLatestEligibleVersion,
41622
+ githubIssueTypeForTitle,
41353
41623
  githubWorkflowBundle,
41354
41624
  hasAnyDocsEmittingBundle,
41355
41625
  hasAnyDownstreamIssueKindBundle,
@@ -41407,10 +41677,14 @@ export {
41407
41677
  renderCustomDocSections,
41408
41678
  renderExtractApiProcedure,
41409
41679
  renderFocusSection,
41680
+ renderGithubIssueTypeSection,
41681
+ renderGithubIssueTypeSectionLines,
41410
41682
  renderIssueTemplatesBundleHook,
41411
41683
  renderIssueTemplatesCheckerScript,
41412
41684
  renderIssueTemplatesRuleContent,
41413
41685
  renderIssueTemplatesStarterPage,
41686
+ renderIssueTypeAssignmentBlanket,
41687
+ renderIssueTypeAssignmentStep,
41414
41688
  renderMeetingTypesSection,
41415
41689
  renderNextRequirementIdProcedure,
41416
41690
  renderPhaseTypeInvariantSection,
@@ -41427,6 +41701,7 @@ export {
41427
41701
  renderScheduledTasksSection,
41428
41702
  renderScopeGateSection,
41429
41703
  renderScopeGateShellHelpers,
41704
+ renderSetIssueTypeFallbackLines,
41430
41705
  renderSharedEditingBundleHook,
41431
41706
  renderSharedEditingHelperScript,
41432
41707
  renderSharedEditingRuleContent,
@@ -41437,6 +41712,7 @@ export {
41437
41712
  renderStripToolArtifactTagsProcedure,
41438
41713
  renderTemporalFramingCheckerScript,
41439
41714
  renderTemporalFramingRuleContent,
41715
+ renderTitlePrefixTypeBullets,
41440
41716
  renderUnblockDependentsScript,
41441
41717
  renderUnblockDependentsSection,
41442
41718
  requirementsAnalystBundle,