@codedrifters/configulator 0.0.182 → 0.0.184

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
@@ -197,6 +197,17 @@ var AGENT_MODEL = {
197
197
  BALANCED: "balanced",
198
198
  POWERFUL: "powerful"
199
199
  };
200
+ function resolveModelAlias(model) {
201
+ if (!model || model === AGENT_MODEL.INHERIT) {
202
+ return void 0;
203
+ }
204
+ const mapping = {
205
+ [AGENT_MODEL.POWERFUL]: "opus",
206
+ [AGENT_MODEL.BALANCED]: "sonnet",
207
+ [AGENT_MODEL.FAST]: "haiku"
208
+ };
209
+ return mapping[model] ?? model;
210
+ }
200
211
  var MCP_TRANSPORT = {
201
212
  STDIO: "stdio",
202
213
  HTTP: "http",
@@ -943,6 +954,849 @@ var jestBundle = {
943
954
  }
944
955
  };
945
956
 
957
+ // src/agent/bundles/meeting-analysis.ts
958
+ var meetingAnalystSubAgent = {
959
+ name: "meeting-analyst",
960
+ description: "Processes meeting transcripts through a 4-phase pipeline: extract, notes, draft, and link",
961
+ model: AGENT_MODEL.POWERFUL,
962
+ maxTurns: 80,
963
+ platforms: { cursor: { exclude: true } },
964
+ prompt: [
965
+ "# Meeting Analyst Agent",
966
+ "",
967
+ "You process meeting transcripts through a structured 4-phase pipeline.",
968
+ "Each phase runs as a **separate agent session**, triggered by its own",
969
+ "GitHub issue with a `meeting:*` phase label. You handle exactly **one",
970
+ "phase per session** \u2014 read the issue to determine which phase to execute.",
971
+ "",
972
+ "## Execution Model",
973
+ "",
974
+ "1. Each meeting produces up to 4 GitHub issues (one per phase)",
975
+ "2. Each issue carries a `meeting:*` label identifying the phase",
976
+ "3. You pick up one issue, execute that phase, commit/push, then close the issue",
977
+ "4. Phase 1 (Extract) creates the downstream phase issues for phases 2-4",
978
+ "5. Each downstream issue includes `Depends on: #N` linking to its predecessor",
979
+ "",
980
+ "## Design Principles",
981
+ "",
982
+ "1. **Extract, don't interpret.** Capture what was said and decided. Flag",
983
+ " ambiguity as open items rather than resolving it.",
984
+ "2. **Route to the right category.** Meeting content maps to requirements,",
985
+ " ADRs, product docs, and business strategy. Each output goes to the",
986
+ " correct location per the project's taxonomy.",
987
+ "3. **Preserve provenance.** Every extracted item links back to the meeting",
988
+ " source so reviewers can check context.",
989
+ "4. **Create issues, not documents.** For requirements and ADRs, create",
990
+ " GitHub issues that other agents or humans will pick up. Do not write",
991
+ " final requirement documents yourself.",
992
+ "5. **Bi-directional traceability.** Every document and issue created by",
993
+ " this pipeline must link back to the meeting source, and the meeting",
994
+ " source documents must link forward to everything created from them.",
995
+ "",
996
+ "---",
997
+ "",
998
+ "## Traceability",
999
+ "",
1000
+ "All outputs must be bi-directionally linked so any artifact can be traced",
1001
+ "back to the meeting that produced it and forward to everything it spawned.",
1002
+ "",
1003
+ "### Backward links (created artifact \u2192 meeting source)",
1004
+ "",
1005
+ "Every GitHub issue and document created by this pipeline must include a",
1006
+ "`## Traceability` section with:",
1007
+ "",
1008
+ "```markdown",
1009
+ "## Traceability",
1010
+ "",
1011
+ "- **Source meeting:** <path to transcript or meeting notes>",
1012
+ "- **Extraction:** <path to extraction file>",
1013
+ "- **Phase issue:** #<N> (the phase issue that created this artifact)",
1014
+ "```",
1015
+ "",
1016
+ "### Forward links (meeting source \u2192 created artifacts)",
1017
+ "",
1018
+ "After Phase 4 (Link) creates all follow-up issues and documents:",
1019
+ "",
1020
+ "1. **Update the extraction file** with a `## Downstream Artifacts` section",
1021
+ " listing every issue and document created from this meeting:",
1022
+ "",
1023
+ " ```markdown",
1024
+ " ## Downstream Artifacts",
1025
+ "",
1026
+ " | Artifact | Type | Issue/Path |",
1027
+ " |----------|------|------------|",
1028
+ " | <title> | requirement / ADR / action-item / profile | #<N> or <path> |",
1029
+ " ```",
1030
+ "",
1031
+ "2. **Update the meeting notes** with a similar `## Related Issues` section",
1032
+ " listing all issues created from this meeting.",
1033
+ "",
1034
+ "3. **Comment on the extract issue** with a summary linking to all created",
1035
+ " artifacts.",
1036
+ "",
1037
+ "### Within-pipeline links",
1038
+ "",
1039
+ "- Phase issues link to predecessors via `Depends on: #N`",
1040
+ "- Phase issues reference the extraction file path in their body",
1041
+ "- Draft documents reference both the extraction and the meeting notes",
1042
+ "",
1043
+ "---",
1044
+ "",
1045
+ "## Phase 1: Extract (`meeting:extract`)",
1046
+ "",
1047
+ "**Goal:** Read the meeting transcript and categorize all substantive content.",
1048
+ "",
1049
+ "### Steps",
1050
+ "",
1051
+ "1. Read the transcript file specified in the issue body.",
1052
+ "2. Identify and categorize content into these buckets:",
1053
+ "",
1054
+ " | Bucket | What to look for |",
1055
+ " |--------|-----------------|",
1056
+ ` | **Decisions** | "We decided...", "Let's go with...", explicit choices |`,
1057
+ ' | **Requirements** | Feature descriptions, acceptance criteria, "it should..." |',
1058
+ " | **Technology discussions** | Platform comparisons, architecture options, tool evaluations |",
1059
+ ' | **Action items** | "[Person] will...", "Next step is...", assigned tasks |',
1060
+ ' | **Open questions** | "We need to figure out...", unresolved debates |',
1061
+ " | **People of interest** | Industry contacts, domain experts mentioned |",
1062
+ " | **Companies of interest** | Competitors, vendors, partners discussed |",
1063
+ " | **Strategic direction** | Business model changes, market positioning |",
1064
+ " | **Product direction** | Roadmap changes, feature prioritization |",
1065
+ "",
1066
+ "3. Write the extraction to a markdown file with structured sections:",
1067
+ " - Attendees",
1068
+ " - Decisions Made (with category and confidence: Firm / Tentative / Needs confirmation)",
1069
+ " - Requirements Identified (with category and priority estimate)",
1070
+ " - Technology Discussions (with status: Decided / Leaning toward / Open)",
1071
+ " - Action Items (with assignee and due date if stated)",
1072
+ " - Open Questions",
1073
+ " - People of Interest (with context and whether a profile exists)",
1074
+ " - Companies of Interest (with type and context)",
1075
+ " - Strategic / Product Direction",
1076
+ "",
1077
+ "4. **Create downstream phase issues** using `gh issue create`:",
1078
+ " - Always create a `meeting:notes` issue (blocked on this extract issue)",
1079
+ " - If requirements OR decisions/ADRs identified, create a `meeting:draft` issue",
1080
+ " (blocked on the notes issue)",
1081
+ " - Always create a `meeting:link` issue \u2014 blocked on the draft issue if one",
1082
+ " was created, otherwise blocked on the notes issue",
1083
+ "",
1084
+ "5. Commit, push, and close the extract issue.",
1085
+ "",
1086
+ "---",
1087
+ "",
1088
+ "## Phase 2: Notes (`meeting:notes`)",
1089
+ "",
1090
+ "**Goal:** Transform the extraction into structured meeting notes.",
1091
+ "",
1092
+ "### Steps",
1093
+ "",
1094
+ "1. Read the extraction file referenced in the issue body (output of Phase 1).",
1095
+ "2. Write structured meeting notes with these sections:",
1096
+ " - Meeting metadata (title, date, attendees)",
1097
+ " - Agenda / topics covered",
1098
+ " - Key Discussion Points (organized by topic)",
1099
+ " - Decisions (numbered, with rationale)",
1100
+ " - Action Items (table: who, what, when)",
1101
+ " - Open Questions",
1102
+ " - Follow-up items",
1103
+ "3. Commit, push, and close the notes issue.",
1104
+ "",
1105
+ "---",
1106
+ "",
1107
+ "## Phase 3: Draft (`meeting:draft`)",
1108
+ "",
1109
+ "**Goal:** Draft proposals for requirements, ADRs, and product/strategy updates.",
1110
+ "",
1111
+ "This phase only exists if the extraction identified requirements, architectural",
1112
+ "decisions, or strategy changes. If this issue exists, execute it.",
1113
+ "",
1114
+ "### Steps",
1115
+ "",
1116
+ "1. Read the extraction file from Phase 1.",
1117
+ "2. Check existing requirement registries and ADR registries for duplicates.",
1118
+ "3. Draft requirement proposals with:",
1119
+ " - Category (FR, BR, NFR, etc.)",
1120
+ " - Summary (2-3 sentences)",
1121
+ " - Draft acceptance criteria",
1122
+ " - Related existing requirements",
1123
+ "4. Draft ADR proposals for technology decisions with:",
1124
+ " - Context and problem statement",
1125
+ " - Options discussed",
1126
+ " - Stated preferences or decisions",
1127
+ " - Status: Proposed or Decided",
1128
+ "5. Summarize product/strategy document updates needed.",
1129
+ "6. Commit, push, and close the draft issue.",
1130
+ "",
1131
+ "---",
1132
+ "",
1133
+ "## Phase 4: Link (`meeting:link`)",
1134
+ "",
1135
+ "**Goal:** Create GitHub issues for follow-up work, cross-reference the",
1136
+ "meeting into existing documentation, and complete bi-directional traceability.",
1137
+ "",
1138
+ "### Steps",
1139
+ "",
1140
+ "1. Read the drafts from Phase 3 (if they exist) and the extraction from Phase 1.",
1141
+ "2. Create requirement issues using `gh issue create` with appropriate labels.",
1142
+ " Include a `## Traceability` section in each issue body linking back to",
1143
+ " the source meeting and extraction file.",
1144
+ "3. Create ADR issues if technology decisions need formal records.",
1145
+ " Include a `## Traceability` section in each.",
1146
+ "4. Create action item issues for tasks that are not document-related.",
1147
+ " Include a `## Traceability` section in each.",
1148
+ "5. Cross-reference the meeting in any existing documents that were discussed.",
1149
+ "6. Apply direct product/strategy doc updates for items flagged as **Firm**",
1150
+ " confidence in the extraction.",
1151
+ "7. **Update the extraction file** with a `## Downstream Artifacts` section",
1152
+ " listing every issue and document created from this meeting.",
1153
+ "8. **Update the meeting notes** with a `## Related Issues` section listing",
1154
+ " all issues created from this meeting.",
1155
+ "9. Comment on the parent extract issue with a summary linking to all",
1156
+ " created artifacts.",
1157
+ "10. Commit and push (if any file changes were made), then close the link issue.",
1158
+ "",
1159
+ "---",
1160
+ "",
1161
+ "## GitHub Integration",
1162
+ "",
1163
+ "- Use `gh` CLI for all GitHub operations",
1164
+ "- Apply the appropriate `meeting:*` phase label to each phase issue",
1165
+ "- Use `type:docs` for documentation-producing issues, `type:chore` for",
1166
+ " maintenance/organizational tasks",
1167
+ "- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)",
1168
+ "- Reference the source meeting transcript in all created issues",
1169
+ "- Link phase issues with `Depends on: #N` to enforce ordering",
1170
+ "",
1171
+ "## When to Shorten the Pipeline",
1172
+ "",
1173
+ "- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session",
1174
+ "- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue",
1175
+ "- **Only action items**: extract + notes + link (3 phase issues)"
1176
+ ].join("\n")
1177
+ };
1178
+ var processMeetingSkill = {
1179
+ name: "process-meeting",
1180
+ description: "Process a meeting transcript through the 4-phase meeting analysis pipeline",
1181
+ disableModelInvocation: true,
1182
+ userInvocable: true,
1183
+ context: "fork",
1184
+ agent: "meeting-analyst",
1185
+ platforms: { cursor: { exclude: true } },
1186
+ instructions: [
1187
+ "# Process Meeting Transcript",
1188
+ "",
1189
+ "Kick off meeting transcript processing by executing Phase 1 (Extract)",
1190
+ "and creating downstream phase issues for the remaining phases.",
1191
+ "",
1192
+ "## Usage",
1193
+ "",
1194
+ "/process-meeting <path-to-transcript>",
1195
+ "",
1196
+ "## Steps",
1197
+ "",
1198
+ "1. Read the provided transcript file",
1199
+ "2. Execute Phase 1 (Extract) \u2014 categorize transcript content into",
1200
+ " decisions, requirements, action items, open questions, and more",
1201
+ "3. Write the extraction to a markdown file",
1202
+ "4. Create downstream phase issues using `gh issue create`:",
1203
+ " - `meeting:notes` issue (always)",
1204
+ " - `meeting:draft` issue (if requirements or decisions were found)",
1205
+ " - `meeting:link` issue (always)",
1206
+ "5. Each downstream issue includes `Depends on:` linking to its predecessor",
1207
+ "6. Commit and push the extraction file",
1208
+ "",
1209
+ "## Input",
1210
+ "",
1211
+ "Provide a path to a meeting transcript file (text or markdown).",
1212
+ "The transcript should contain speaker-attributed dialogue.",
1213
+ "",
1214
+ "## Output",
1215
+ "",
1216
+ "- An extraction markdown file with categorized meeting content",
1217
+ "- Phase issues with `meeting:*` labels for downstream agent sessions",
1218
+ " to pick up (notes, draft, link)"
1219
+ ].join("\n")
1220
+ };
1221
+ var meetingAnalysisBundle = {
1222
+ name: "meeting-analysis",
1223
+ description: "Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)",
1224
+ appliesWhen: () => true,
1225
+ rules: [
1226
+ {
1227
+ name: "meeting-processing-workflow",
1228
+ description: "Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions",
1229
+ scope: AGENT_RULE_SCOPE.ALWAYS,
1230
+ content: [
1231
+ "# Meeting Processing Workflow",
1232
+ "",
1233
+ "Use `/process-meeting <path>` to process a meeting transcript through a",
1234
+ "4-phase pipeline (extract \u2192 notes \u2192 draft \u2192 link). Each phase runs as a",
1235
+ "separate agent session tracked by a GitHub issue with a `meeting:*` label.",
1236
+ "See the `meeting-analyst` agent definition for full workflow details."
1237
+ ].join("\n"),
1238
+ platforms: {
1239
+ cursor: { exclude: true }
1240
+ },
1241
+ tags: ["workflow"]
1242
+ }
1243
+ ],
1244
+ skills: [processMeetingSkill],
1245
+ subAgents: [meetingAnalystSubAgent]
1246
+ };
1247
+
1248
+ // src/agent/bundles/orchestrator.ts
1249
+ var checkBlockedProcedure = {
1250
+ name: "check-blocked.sh",
1251
+ description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, prs",
1252
+ content: [
1253
+ "#!/usr/bin/env bash",
1254
+ "# check-blocked.sh \u2014 Token-efficient issue triage for agent loops.",
1255
+ "# Replaces inline body-parsing with shell pipelines that return only",
1256
+ "# actionable summaries.",
1257
+ "#",
1258
+ "# Usage:",
1259
+ "# .claude/procedures/check-blocked.sh unblock",
1260
+ "# .claude/procedures/check-blocked.sh eligible",
1261
+ "# .claude/procedures/check-blocked.sh stale",
1262
+ "# .claude/procedures/check-blocked.sh orphaned",
1263
+ "# .claude/procedures/check-blocked.sh prs",
1264
+ "",
1265
+ "set -uo pipefail",
1266
+ "",
1267
+ "# \u2500\u2500 constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1268
+ "",
1269
+ "STALE_IN_PROGRESS_HOURS=72",
1270
+ "STALE_BLOCKED_HOURS=168",
1271
+ "",
1272
+ "# \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1273
+ "",
1274
+ '# Extract issue numbers from a "Depends on:" line.',
1275
+ '# Returns space-separated numbers, or empty string for "(none)".',
1276
+ "parse_deps() {",
1277
+ ' local line="$1"',
1278
+ ` if echo "$line" | grep -qi '(none)'; then`,
1279
+ ' echo ""',
1280
+ " return",
1281
+ " fi",
1282
+ ` echo "$line" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\n' ' ' || echo ""`,
1283
+ "}",
1284
+ "",
1285
+ "# Check if a single issue is closed. Returns 0 if closed, 1 if open.",
1286
+ "is_closed() {",
1287
+ " local state",
1288
+ ` state=$(gh issue view "$1" --json state --jq '.state' 2>/dev/null || echo "UNKNOWN")`,
1289
+ ' [[ "$state" == "CLOSED" ]]',
1290
+ "}",
1291
+ "",
1292
+ "# \u2500\u2500 subcommands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1293
+ "",
1294
+ "cmd_unblock() {",
1295
+ " local issues",
1296
+ ' issues=$(gh issue list --label "status:blocked" --state open \\',
1297
+ ' --json number,body --limit 50 2>/dev/null || echo "[]")',
1298
+ "",
1299
+ " local count",
1300
+ ` count=$(echo "$issues" | jq 'length')`,
1301
+ ' if [[ "$count" -eq 0 ]]; then',
1302
+ ' echo "NO_BLOCKED_ISSUES"',
1303
+ " return 0",
1304
+ " fi",
1305
+ "",
1306
+ " local issue_data",
1307
+ ` issue_data=$(echo "$issues" | jq -r '`,
1308
+ " .[] |",
1309
+ ' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | .[0] // "") as $dep_line |',
1310
+ ' "\\(.number)\\t\\($dep_line)"',
1311
+ " ')",
1312
+ "",
1313
+ " while IFS=$'\\t' read -r num dep_line; do",
1314
+ ' [[ -z "$num" ]] && continue',
1315
+ "",
1316
+ ' if [[ -z "$dep_line" ]]; then',
1317
+ ' echo "BLOCKED #${num} \u2014 no Depends on field found"',
1318
+ " continue",
1319
+ " fi",
1320
+ "",
1321
+ " local deps",
1322
+ ' deps=$(parse_deps "$dep_line")',
1323
+ ' if [[ -z "${deps// /}" ]]; then',
1324
+ ' echo "UNBLOCK #${num} \u2014 no dependencies"',
1325
+ " continue",
1326
+ " fi",
1327
+ "",
1328
+ " local all_closed=true",
1329
+ ' local open_deps=""',
1330
+ ' local closed_deps=""',
1331
+ " for dep in $deps; do",
1332
+ ' if is_closed "$dep"; then',
1333
+ ' closed_deps="${closed_deps}#${dep} "',
1334
+ " else",
1335
+ " all_closed=false",
1336
+ ' open_deps="${open_deps}#${dep} "',
1337
+ " fi",
1338
+ " done",
1339
+ "",
1340
+ " if $all_closed; then",
1341
+ ' echo "UNBLOCK #${num} \u2014 all deps closed (${closed_deps% })"',
1342
+ " else",
1343
+ ' echo "BLOCKED #${num} \u2014 waiting on ${open_deps% }"',
1344
+ " fi",
1345
+ ' done <<< "$issue_data"',
1346
+ "}",
1347
+ "",
1348
+ "cmd_eligible() {",
1349
+ " local issues",
1350
+ ' issues=$(gh issue list --label "status:ready" --state open \\',
1351
+ ' --search "sort:created-asc" \\',
1352
+ ' --json number,title,body,labels --limit 50 2>/dev/null || echo "[]")',
1353
+ "",
1354
+ " local count",
1355
+ ` count=$(echo "$issues" | jq 'length')`,
1356
+ ' if [[ "$count" -eq 0 ]]; then',
1357
+ ' echo "NO_READY_ISSUES"',
1358
+ " return 0",
1359
+ " fi",
1360
+ "",
1361
+ " local issue_data",
1362
+ ` issue_data=$(echo "$issues" | jq -r '`,
1363
+ " .[] |",
1364
+ ' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | .[0] // "") as $dep_line |',
1365
+ ' (.labels | map(.name) | join(",")) as $label_str |',
1366
+ ' (.labels | map(.name) | map(select(startswith("type:"))) | .[0] // "") as $type_label |',
1367
+ ' "\\(.number)\\t\\(.title)\\t\\($dep_line)\\t\\($label_str)\\t\\($type_label)"',
1368
+ " ')",
1369
+ "",
1370
+ ' local results=""',
1371
+ " while IFS=$'\\t' read -r num title dep_line labels_str type_label; do",
1372
+ ' [[ -z "$num" ]] && continue',
1373
+ "",
1374
+ ' local deps=""',
1375
+ ' if [[ -n "$dep_line" ]]; then',
1376
+ ' deps=$(parse_deps "$dep_line")',
1377
+ " fi",
1378
+ "",
1379
+ " # Check if any dep is still open.",
1380
+ " local has_open_dep=false",
1381
+ ' local open_deps=""',
1382
+ ' if [[ -n "${deps// /}" ]]; then',
1383
+ " for dep in $deps; do",
1384
+ ' if ! is_closed "$dep"; then',
1385
+ " has_open_dep=true",
1386
+ ' open_deps="${open_deps}#${dep} "',
1387
+ " fi",
1388
+ " done",
1389
+ " fi",
1390
+ "",
1391
+ " if $has_open_dep; then",
1392
+ ' echo "SKIP #${num} \u2014 dep ${open_deps% } still open"',
1393
+ " continue",
1394
+ " fi",
1395
+ "",
1396
+ " # 5-level priority sort key.",
1397
+ " local sort_key=2",
1398
+ ' local priority="medium"',
1399
+ ' case "$labels_str" in',
1400
+ ' *priority:critical*) sort_key=0; priority="critical" ;;',
1401
+ ' *priority:high*) sort_key=1; priority="high" ;;',
1402
+ ' *priority:medium*) sort_key=2; priority="medium" ;;',
1403
+ ' *priority:low*) sort_key=3; priority="low" ;;',
1404
+ ' *priority:trivial*) sort_key=4; priority="trivial" ;;',
1405
+ " esac",
1406
+ "",
1407
+ ' local label_info=""',
1408
+ ' [[ -n "$type_label" ]] && label_info=" ${type_label}"',
1409
+ "",
1410
+ ' results="${results}${sort_key}\\t${num}\\tPICK #${num} priority:${priority}${label_info} \\"${title}\\"\\n"',
1411
+ ' done <<< "$issue_data"',
1412
+ "",
1413
+ " # Sort by priority, then issue number (FIFO).",
1414
+ ' if [[ -n "$results" ]]; then',
1415
+ ` printf '%b' "$results" | sort -t$'\\t' -k1,1n -k2,2n | cut -f3`,
1416
+ " fi",
1417
+ "}",
1418
+ "",
1419
+ "cmd_stale() {",
1420
+ " # Check in-progress issues",
1421
+ " local ip_issues",
1422
+ ' ip_issues=$(gh issue list --label "status:in-progress" --state open \\',
1423
+ ' --json number,title,updatedAt --limit 50 2>/dev/null || echo "[]")',
1424
+ "",
1425
+ " local ip_count",
1426
+ ` ip_count=$(echo "$ip_issues" | jq 'length')`,
1427
+ "",
1428
+ ' if [[ "$ip_count" -gt 0 ]]; then',
1429
+ " local ip_threshold",
1430
+ " ip_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\",
1431
+ ' || date -u -d "${STALE_IN_PROGRESS_HOURS} hours ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',
1432
+ "",
1433
+ " local ip_data",
1434
+ ` ip_data=$(echo "$ip_issues" | jq -r '.[] | "\\(.number)\\t\\(.title)\\t\\(.updatedAt)"')`,
1435
+ "",
1436
+ " while IFS=$'\\t' read -r num title updated; do",
1437
+ ' [[ -z "$num" ]] && continue',
1438
+ ' local updated_trimmed="${updated%%+*}"',
1439
+ ' updated_trimmed="${updated_trimmed%%Z*}"',
1440
+ ' if [[ "$updated_trimmed" < "$ip_threshold" ]]; then',
1441
+ ' local date_part="${updated_trimmed%%T*}"',
1442
+ ' echo "STALE #${num} \u2014 no activity since ${date_part} \u2014 \\"${title}\\""',
1443
+ " fi",
1444
+ ' done <<< "$ip_data"',
1445
+ " fi",
1446
+ "",
1447
+ " # Check blocked issues",
1448
+ " local bl_issues",
1449
+ ' bl_issues=$(gh issue list --label "status:blocked" --state open \\',
1450
+ ' --json number,title,updatedAt --limit 50 2>/dev/null || echo "[]")',
1451
+ "",
1452
+ " local bl_count",
1453
+ ` bl_count=$(echo "$bl_issues" | jq 'length')`,
1454
+ "",
1455
+ ' if [[ "$bl_count" -gt 0 ]]; then',
1456
+ " local bl_threshold",
1457
+ " bl_threshold=$(date -u -v-${STALE_BLOCKED_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\",
1458
+ ' || date -u -d "${STALE_BLOCKED_HOURS} hours ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',
1459
+ "",
1460
+ " local bl_data",
1461
+ ` bl_data=$(echo "$bl_issues" | jq -r '.[] | "\\(.number)\\t\\(.title)\\t\\(.updatedAt)"')`,
1462
+ "",
1463
+ " while IFS=$'\\t' read -r num title updated; do",
1464
+ ' [[ -z "$num" ]] && continue',
1465
+ ' local updated_trimmed="${updated%%+*}"',
1466
+ ' updated_trimmed="${updated_trimmed%%Z*}"',
1467
+ ' if [[ "$updated_trimmed" < "$bl_threshold" ]]; then',
1468
+ ' local date_part="${updated_trimmed%%T*}"',
1469
+ ' echo "STALE_BLOCKED #${num} \u2014 blocked since ${date_part} \u2014 \\"${title}\\""',
1470
+ " fi",
1471
+ ' done <<< "$bl_data"',
1472
+ " fi",
1473
+ "",
1474
+ ' if [[ "$ip_count" -eq 0 && "$bl_count" -eq 0 ]]; then',
1475
+ ' echo "NO_STALE_ISSUES"',
1476
+ " fi",
1477
+ "}",
1478
+ "",
1479
+ "cmd_orphaned() {",
1480
+ " # Check for remote branches whose issues are closed or missing",
1481
+ " git fetch --prune origin 2>/dev/null",
1482
+ " local branches",
1483
+ ' branches=$(git branch -r --format="%(refname:short)" | grep -v HEAD | sed "s|origin/||")',
1484
+ "",
1485
+ " local found_orphan=false",
1486
+ " while IFS= read -r branch; do",
1487
+ ' [[ -z "$branch" ]] && continue',
1488
+ ' [[ "$branch" == "main" || "$branch" == "master" ]] && continue',
1489
+ "",
1490
+ " # Extract issue number from branch name (e.g., feat/42-add-login \u2192 42)",
1491
+ " local issue_num",
1492
+ ` issue_num=$(echo "$branch" | grep -oE '/[0-9]+' | tr -d '/' | head -1)`,
1493
+ ' [[ -z "$issue_num" ]] && continue',
1494
+ "",
1495
+ " local state",
1496
+ ` state=$(gh issue view "$issue_num" --json state --jq '.state' 2>/dev/null || echo "NOT_FOUND")`,
1497
+ "",
1498
+ ' if [[ "$state" == "CLOSED" ]]; then',
1499
+ " found_orphan=true",
1500
+ ' echo "ORPHAN_BRANCH ${branch} \u2014 issue #${issue_num} is closed"',
1501
+ ' elif [[ "$state" == "NOT_FOUND" ]]; then',
1502
+ " found_orphan=true",
1503
+ ' echo "ORPHAN_BRANCH ${branch} \u2014 issue #${issue_num} not found"',
1504
+ " fi",
1505
+ ' done <<< "$branches"',
1506
+ "",
1507
+ " # Check for open PRs whose linked issues are closed",
1508
+ " local prs",
1509
+ ' prs=$(gh pr list --state open --json number,title,body --limit 50 2>/dev/null || echo "[]")',
1510
+ " local pr_data",
1511
+ ` pr_data=$(echo "$prs" | jq -r '`,
1512
+ " .[] |",
1513
+ ' (.body | capture("(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)") | .num) as $issue |',
1514
+ ' "\\(.number)\\t\\(.title)\\t\\($issue // "")"',
1515
+ " ' 2>/dev/null)",
1516
+ "",
1517
+ " while IFS=$'\\t' read -r pr_num title issue_num; do",
1518
+ ' [[ -z "$pr_num" || -z "$issue_num" ]] && continue',
1519
+ ' if is_closed "$issue_num"; then',
1520
+ " found_orphan=true",
1521
+ ' echo "ORPHAN_PR #${pr_num} \u2014 linked issue #${issue_num} is closed \u2014 \\"${title}\\""',
1522
+ " fi",
1523
+ ' done <<< "$pr_data"',
1524
+ "",
1525
+ " if ! $found_orphan; then",
1526
+ ' echo "NO_ORPHANED_RESOURCES"',
1527
+ " fi",
1528
+ "}",
1529
+ "",
1530
+ "cmd_prs() {",
1531
+ " local prs",
1532
+ " prs=$(gh pr list --state open --json number,title,isDraft,headRefName,labels,body \\",
1533
+ ' --limit 50 2>/dev/null || echo "[]")',
1534
+ "",
1535
+ " local count",
1536
+ ` count=$(echo "$prs" | jq 'length')`,
1537
+ ' if [[ "$count" -eq 0 ]]; then',
1538
+ ' echo "NO_OPEN_PRS"',
1539
+ " return 0",
1540
+ " fi",
1541
+ "",
1542
+ " # Filter: not draft, no needs-attention label.",
1543
+ " local eligible",
1544
+ ` eligible=$(echo "$prs" | jq -r '`,
1545
+ " .[] |",
1546
+ " select(.isDraft == false) |",
1547
+ ' select(.labels | map(.name) | index("status:needs-attention") | not) |',
1548
+ ' (.body | capture("(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)") | .num) as $issue |',
1549
+ ' "\\(.number)\\t\\(.title)\\t\\(.headRefName)\\t\\($issue // "")"',
1550
+ " ' 2>/dev/null)",
1551
+ "",
1552
+ ' if [[ -z "$eligible" ]]; then',
1553
+ ' echo "NO_ELIGIBLE_PRS"',
1554
+ " return 0",
1555
+ " fi",
1556
+ "",
1557
+ " while IFS=$'\\t' read -r pr_num title branch issue_num; do",
1558
+ ' [[ -z "$pr_num" ]] && continue',
1559
+ "",
1560
+ ' if [[ -z "$issue_num" ]]; then',
1561
+ ' echo "SKIP PR #${pr_num} \u2014 no linked issue \u2014 \\"${title}\\""',
1562
+ " continue",
1563
+ " fi",
1564
+ "",
1565
+ " # Check CI status",
1566
+ " local failing_checks",
1567
+ ' failing_checks=$(gh pr checks "$pr_num" --json name,state \\',
1568
+ ` --jq '[.[] | select(.state != "SUCCESS" and .state != "SKIPPED")] | length' 2>/dev/null || echo "-1")`,
1569
+ "",
1570
+ ' if [[ "$failing_checks" == "-1" ]]; then',
1571
+ ' echo "SKIP PR #${pr_num} \u2014 could not read CI status \u2014 \\"${title}\\""',
1572
+ " continue",
1573
+ " fi",
1574
+ "",
1575
+ ' if [[ "$failing_checks" -gt 0 ]]; then',
1576
+ ' echo "SKIP PR #${pr_num} \u2014 ${failing_checks} CI check(s) not passing \u2014 \\"${title}\\""',
1577
+ " continue",
1578
+ " fi",
1579
+ "",
1580
+ " # Check if already approved",
1581
+ " local approved",
1582
+ ' approved=$(gh pr view "$pr_num" --json reviews \\',
1583
+ ` --jq '[.reviews[] | select(.state == "APPROVED")] | length' 2>/dev/null || echo "0")`,
1584
+ ' if [[ "$approved" -gt 0 ]]; then',
1585
+ ' echo "SKIP PR #${pr_num} \u2014 already approved \u2014 \\"${title}\\""',
1586
+ " continue",
1587
+ " fi",
1588
+ "",
1589
+ ' echo "REVIEW PR #${pr_num} issue:#${issue_num} branch:${branch} \u2014 \\"${title}\\""',
1590
+ ' done <<< "$eligible"',
1591
+ "}",
1592
+ "",
1593
+ "# \u2500\u2500 main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1594
+ "",
1595
+ 'case "${1:-help}" in',
1596
+ ' unblock) shift; cmd_unblock "$@" ;;',
1597
+ ' eligible) shift; cmd_eligible "$@" ;;',
1598
+ ' stale) shift; cmd_stale "$@" ;;',
1599
+ ' orphaned) shift; cmd_orphaned "$@" ;;',
1600
+ ' prs) shift; cmd_prs "$@" ;;',
1601
+ " help|*)",
1602
+ ' echo "Usage: check-blocked.sh <unblock|eligible|stale|orphaned|prs>"',
1603
+ " exit 1",
1604
+ " ;;",
1605
+ "esac"
1606
+ ].join("\n")
1607
+ };
1608
+ var orchestratorSubAgent = {
1609
+ name: "orchestrator",
1610
+ description: "Pipeline manager that reviews PRs, triages issues, and identifies the next work item \u2014 never implements code",
1611
+ model: AGENT_MODEL.POWERFUL,
1612
+ maxTurns: 100,
1613
+ platforms: { cursor: { exclude: true } },
1614
+ prompt: [
1615
+ "# Orchestrator Agent",
1616
+ "",
1617
+ "You are a pipeline manager for the **{{repository.owner}}/{{repository.name}}** repository.",
1618
+ "You review PRs, triage issues, and identify the next work item. You **never**",
1619
+ "implement code, create branches for issues, or claim issues.",
1620
+ "",
1621
+ "Run the same loop every invocation. Execute all phases in order.",
1622
+ "",
1623
+ "---",
1624
+ "",
1625
+ "## Phase A: Startup",
1626
+ "",
1627
+ "```bash",
1628
+ "git checkout main && git pull origin main",
1629
+ "```",
1630
+ "",
1631
+ "## Phase B: Batch PR Review",
1632
+ "",
1633
+ "Find all PRs eligible for review:",
1634
+ "",
1635
+ "```bash",
1636
+ ".claude/procedures/check-blocked.sh prs",
1637
+ "```",
1638
+ "",
1639
+ "For each `REVIEW PR #N issue:#M branch:<branch>` line:",
1640
+ "",
1641
+ "1. Check out the PR branch: `gh pr checkout N`",
1642
+ "2. Review the PR:",
1643
+ " - Read the PR description and linked issue: `gh pr view N`",
1644
+ " - Review the diff: `gh pr diff N`",
1645
+ " - Check all changed files for correctness, conventions, and test coverage",
1646
+ " - Verify PR conventions: conventional commit title, closing keyword, summary present",
1647
+ " - Check CI status: `gh pr checks N`",
1648
+ "3. If the PR passes review:",
1649
+ " - Approve: `gh pr review N --approve --body '<summary>'`",
1650
+ " - Enable auto-merge: `gh pr merge N --auto --squash`",
1651
+ "4. If the PR fails review:",
1652
+ " - Request changes: `gh pr review N --request-changes --body '<findings>'`",
1653
+ "5. After each PR (whether merged or not):",
1654
+ " ```bash",
1655
+ " git checkout main && git pull origin main",
1656
+ " ```",
1657
+ "",
1658
+ "Skip lines starting with `SKIP` \u2014 those PRs are not eligible.",
1659
+ "If output is `NO_OPEN_PRS` or `NO_ELIGIBLE_PRS`, skip to Phase C.",
1660
+ "",
1661
+ "## Phase C: Triage \u2014 Unblock",
1662
+ "",
1663
+ "Check for blocked issues whose dependencies have resolved:",
1664
+ "",
1665
+ "```bash",
1666
+ ".claude/procedures/check-blocked.sh unblock",
1667
+ "```",
1668
+ "",
1669
+ "For each `UNBLOCK #N` line:",
1670
+ "```bash",
1671
+ 'gh issue edit N --remove-label "status:blocked" --add-label "status:ready"',
1672
+ 'gh issue comment N --body "Dependencies resolved \u2014 unblocking."',
1673
+ "```",
1674
+ "",
1675
+ "For `BLOCKED #N \u2014 no Depends on field found`: leave as-is (Phase D will",
1676
+ "catch it if it's been blocked too long).",
1677
+ "",
1678
+ "If output is `NO_BLOCKED_ISSUES`, skip to Phase D.",
1679
+ "",
1680
+ "## Phase D: Maintenance",
1681
+ "",
1682
+ "### D1: Stale Detection",
1683
+ "",
1684
+ "```bash",
1685
+ ".claude/procedures/check-blocked.sh stale",
1686
+ "```",
1687
+ "",
1688
+ "For each `STALE #N` line (in-progress >72h without activity):",
1689
+ "```bash",
1690
+ 'gh issue edit N --add-label "status:needs-attention"',
1691
+ 'gh issue comment N --body "Flagged: in-progress for >3 days with no activity."',
1692
+ "```",
1693
+ "",
1694
+ "For each `STALE_BLOCKED #N` line (blocked >168h):",
1695
+ "```bash",
1696
+ 'gh issue edit N --add-label "status:needs-attention"',
1697
+ 'gh issue comment N --body "Flagged: blocked for >7 days \u2014 may need human intervention."',
1698
+ "```",
1699
+ "",
1700
+ "**Important:** Do NOT auto-reset stale issues to `status:ready` \u2014 partial",
1701
+ "implementation work may exist on a branch.",
1702
+ "",
1703
+ "### D2: Orphaned Detection",
1704
+ "",
1705
+ "```bash",
1706
+ ".claude/procedures/check-blocked.sh orphaned",
1707
+ "```",
1708
+ "",
1709
+ "Report any `ORPHAN_BRANCH` or `ORPHAN_PR` lines. These indicate branches",
1710
+ "or PRs whose linked issues are closed or missing. Log them for visibility",
1711
+ "but do not delete branches automatically.",
1712
+ "",
1713
+ "### D3: Needs-Attention Summary",
1714
+ "",
1715
+ "List all issues currently flagged:",
1716
+ "```bash",
1717
+ 'gh issue list --label "status:needs-attention" --state open --json number,title',
1718
+ "```",
1719
+ "",
1720
+ "Log the count and titles for operator visibility.",
1721
+ "",
1722
+ "## Phase E: Queue Scan",
1723
+ "",
1724
+ "Find the highest-priority ready issue:",
1725
+ "",
1726
+ "```bash",
1727
+ ".claude/procedures/check-blocked.sh eligible",
1728
+ "```",
1729
+ "",
1730
+ "If a `PICK` line is returned, report it as:",
1731
+ "```",
1732
+ 'NEXT_WORK_ITEM #<number> priority:<level> type:<label> "<title>"',
1733
+ "```",
1734
+ "",
1735
+ "If output is `NO_READY_ISSUES`, report that the queue is empty.",
1736
+ "",
1737
+ "**Do NOT claim the issue, create a branch, or start implementation.**",
1738
+ "The worker agent handles that.",
1739
+ "",
1740
+ "## Phase F: Cleanup",
1741
+ "",
1742
+ "```bash",
1743
+ "git checkout main && git pull origin main",
1744
+ "git fetch --prune origin",
1745
+ "```",
1746
+ "",
1747
+ "Log completion: phases executed, PRs reviewed, issues unblocked,",
1748
+ "stale issues flagged, and next work item (if any).",
1749
+ "",
1750
+ "---",
1751
+ "",
1752
+ "## Rules",
1753
+ "",
1754
+ "1. **Never implement code.** You triage, review, and report \u2014 you do not code.",
1755
+ "2. **Never claim issues.** Do not add `status:in-progress` or create branches for issues.",
1756
+ "3. **Always use check-blocked.sh.** All triage queries go through the shell script for token efficiency.",
1757
+ "4. **Follow CLAUDE.md conventions** for all git and gh operations.",
1758
+ "5. **Priority order:** critical > high > medium > low > trivial, then FIFO by issue number."
1759
+ ].join("\n")
1760
+ };
1761
+ var orchestratorBundle = {
1762
+ name: "orchestrator",
1763
+ description: "Pipeline orchestrator agent for issue triage, PR review, and queue management",
1764
+ // Always included by default
1765
+ appliesWhen: () => true,
1766
+ rules: [
1767
+ {
1768
+ name: "orchestrator-conventions",
1769
+ description: "Guidelines for orchestrator agent behavior and pipeline management",
1770
+ scope: AGENT_RULE_SCOPE.ALWAYS,
1771
+ content: [
1772
+ "# Orchestrator Conventions",
1773
+ "",
1774
+ "When running the orchestrator agent (`.claude/agents/orchestrator.md`):",
1775
+ "",
1776
+ "- The orchestrator **never** implements code or creates branches for issues",
1777
+ "- It reviews PRs, triages issues, and reports the next work item",
1778
+ "- All triage queries use `.claude/procedures/check-blocked.sh` for token efficiency",
1779
+ "- Priority order: critical > high > medium > low > trivial, then FIFO",
1780
+ "- Stale thresholds: 72h for in-progress, 168h for blocked",
1781
+ "- Flagged issues get `status:needs-attention` \u2014 they are not auto-reset"
1782
+ ].join("\n"),
1783
+ platforms: {
1784
+ claude: { target: "claude-md" },
1785
+ cursor: { exclude: true }
1786
+ },
1787
+ tags: ["workflow"]
1788
+ }
1789
+ ],
1790
+ subAgents: [orchestratorSubAgent],
1791
+ procedures: [checkBlockedProcedure],
1792
+ claudePermissions: {
1793
+ allow: [
1794
+ // Allow executing the check-blocked.sh procedure
1795
+ "Bash(.claude/procedures/*.sh *)"
1796
+ ]
1797
+ }
1798
+ };
1799
+
946
1800
  // src/pnpm/pnpm-workspace.ts
947
1801
  import { relative } from "path";
948
1802
  import { Component, YamlFile } from "projen";
@@ -1959,7 +2813,9 @@ var BUILT_IN_BUNDLES = [
1959
2813
  awsCdkBundle,
1960
2814
  projenBundle,
1961
2815
  githubWorkflowBundle,
1962
- slackBundle
2816
+ slackBundle,
2817
+ meetingAnalysisBundle,
2818
+ orchestratorBundle
1963
2819
  ];
1964
2820
 
1965
2821
  // src/agent/bundles/scope.ts
@@ -2082,12 +2938,15 @@ var ClaudeRenderer = class _ClaudeRenderer {
2082
2938
  /**
2083
2939
  * Render all Claude Code configuration files.
2084
2940
  */
2085
- static render(component, rules, skills, subAgents, mcpServers, settings) {
2941
+ static render(component, rules, skills, subAgents, mcpServers, settings, procedures) {
2086
2942
  _ClaudeRenderer.renderClaudeMd(component, rules);
2087
2943
  _ClaudeRenderer.renderScopedRules(component, rules);
2088
2944
  _ClaudeRenderer.renderSettings(component, mcpServers, settings);
2089
2945
  _ClaudeRenderer.renderSkills(component, skills);
2090
2946
  _ClaudeRenderer.renderSubAgents(component, subAgents);
2947
+ if (procedures && procedures.length > 0) {
2948
+ _ClaudeRenderer.renderProcedures(component, procedures);
2949
+ }
2091
2950
  }
2092
2951
  static renderClaudeMd(component, rules) {
2093
2952
  const claudeMdRules = rules.filter((r) => {
@@ -2291,6 +3150,7 @@ var ClaudeRenderer = class _ClaudeRenderer {
2291
3150
  }
2292
3151
  static renderSkills(component, skills) {
2293
3152
  for (const skill of skills) {
3153
+ if (skill.platforms?.claude?.exclude) continue;
2294
3154
  const lines = [];
2295
3155
  lines.push("---");
2296
3156
  lines.push(`name: "${skill.name}"`);
@@ -2301,8 +3161,9 @@ var ClaudeRenderer = class _ClaudeRenderer {
2301
3161
  if (skill.userInvocable === false) {
2302
3162
  lines.push(`user-invocable: false`);
2303
3163
  }
2304
- if (skill.model) {
2305
- lines.push(`model: "${skill.model}"`);
3164
+ const resolvedSkillModel = resolveModelAlias(skill.model);
3165
+ if (resolvedSkillModel) {
3166
+ lines.push(`model: "${resolvedSkillModel}"`);
2306
3167
  }
2307
3168
  if (skill.effort) {
2308
3169
  lines.push(`effort: "${skill.effort}"`);
@@ -2344,8 +3205,9 @@ var ClaudeRenderer = class _ClaudeRenderer {
2344
3205
  lines.push(`name: ${agent.name}`);
2345
3206
  lines.push(`description: >-`);
2346
3207
  lines.push(` ${agent.description}`);
2347
- if (agent.model) {
2348
- lines.push(`model: ${agent.model}`);
3208
+ const resolvedModel = resolveModelAlias(agent.model);
3209
+ if (resolvedModel) {
3210
+ lines.push(`model: ${resolvedModel}`);
2349
3211
  }
2350
3212
  if (agent.tools && agent.tools.length > 0) {
2351
3213
  lines.push(`tools:`);
@@ -2401,6 +3263,14 @@ var ClaudeRenderer = class _ClaudeRenderer {
2401
3263
  if (config.env) server.env = { ...config.env };
2402
3264
  return server;
2403
3265
  }
3266
+ static renderProcedures(component, procedures) {
3267
+ for (const proc of procedures) {
3268
+ new TextFile2(component, `.claude/procedures/${proc.name}`, {
3269
+ lines: proc.content.split("\n"),
3270
+ executable: true
3271
+ });
3272
+ }
3273
+ }
2404
3274
  /**
2405
3275
  * Determine the default Claude rule target based on rule scope.
2406
3276
  * ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.
@@ -2458,6 +3328,7 @@ var CursorRenderer = class _CursorRenderer {
2458
3328
  }
2459
3329
  static renderSkills(component, skills) {
2460
3330
  for (const skill of skills) {
3331
+ if (skill.platforms?.cursor?.exclude) continue;
2461
3332
  const lines = [];
2462
3333
  lines.push("---");
2463
3334
  lines.push(`name: "${skill.name}"`);
@@ -2499,9 +3370,6 @@ var CursorRenderer = class _CursorRenderer {
2499
3370
  lines.push(`name: ${agent.name}`);
2500
3371
  lines.push(`description: >-`);
2501
3372
  lines.push(` ${agent.description}`);
2502
- if (agent.model) {
2503
- lines.push(`model: ${agent.model}`);
2504
- }
2505
3373
  if (agent.platforms?.cursor?.readonly) {
2506
3374
  lines.push(`readonly: true`);
2507
3375
  }
@@ -2756,6 +3624,7 @@ var AgentConfig = class _AgentConfig extends Component8 {
2756
3624
  const rules = this.resolveRules();
2757
3625
  const skills = this.resolveSkills();
2758
3626
  const subAgents = this.resolveSubAgents();
3627
+ const procedures = this.resolveProcedures();
2759
3628
  const mcpServers = this.options.mcpServers ?? {};
2760
3629
  const projectMetadata = ProjectMetadata.of(this.project);
2761
3630
  const metadata = projectMetadata?.metadata;
@@ -2765,6 +3634,10 @@ var AgentConfig = class _AgentConfig extends Component8 {
2765
3634
  subAgents,
2766
3635
  metadata
2767
3636
  );
3637
+ const resolvedProcedures = this.resolveProcedureTemplates(
3638
+ procedures,
3639
+ metadata
3640
+ );
2768
3641
  if (platforms.includes(AGENT_PLATFORM.CURSOR)) {
2769
3642
  CursorRenderer.render(
2770
3643
  this,
@@ -2786,7 +3659,8 @@ var AgentConfig = class _AgentConfig extends Component8 {
2786
3659
  _AgentConfig.mergeClaudeDefaults(
2787
3660
  this.options.claudeSettings,
2788
3661
  bundlePermissions
2789
- )
3662
+ ),
3663
+ resolvedProcedures
2790
3664
  );
2791
3665
  }
2792
3666
  if (platforms.includes(AGENT_PLATFORM.CODEX)) {
@@ -2899,6 +3773,16 @@ ${extra}`
2899
3773
  }
2900
3774
  }
2901
3775
  }
3776
+ if (this.options.includeBundles) {
3777
+ for (const bundleName of this.options.includeBundles) {
3778
+ const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
3779
+ if (bundle?.skills) {
3780
+ for (const skill of bundle.skills) {
3781
+ skillMap.set(skill.name, skill);
3782
+ }
3783
+ }
3784
+ }
3785
+ }
2902
3786
  if (this.options.skills) {
2903
3787
  for (const skill of this.options.skills) {
2904
3788
  skillMap.set(skill.name, skill);
@@ -2918,6 +3802,16 @@ ${extra}`
2918
3802
  }
2919
3803
  }
2920
3804
  }
3805
+ if (this.options.includeBundles) {
3806
+ for (const bundleName of this.options.includeBundles) {
3807
+ const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
3808
+ if (bundle?.subAgents) {
3809
+ for (const agent of bundle.subAgents) {
3810
+ agentMap.set(agent.name, agent);
3811
+ }
3812
+ }
3813
+ }
3814
+ }
2921
3815
  if (this.options.subAgents) {
2922
3816
  for (const agent of this.options.subAgents) {
2923
3817
  agentMap.set(agent.name, agent);
@@ -2925,6 +3819,35 @@ ${extra}`
2925
3819
  }
2926
3820
  return [...agentMap.values()];
2927
3821
  }
3822
+ resolveProcedures() {
3823
+ const procMap = /* @__PURE__ */ new Map();
3824
+ if (this.options.autoDetectBundles !== false) {
3825
+ for (const bundle of BUILT_IN_BUNDLES) {
3826
+ if (this.options.excludeBundles?.includes(bundle.name)) continue;
3827
+ if (bundle.appliesWhen(this.project) && bundle.procedures) {
3828
+ for (const proc of bundle.procedures) {
3829
+ procMap.set(proc.name, proc);
3830
+ }
3831
+ }
3832
+ }
3833
+ }
3834
+ if (this.options.includeBundles) {
3835
+ for (const bundleName of this.options.includeBundles) {
3836
+ const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
3837
+ if (bundle?.procedures) {
3838
+ for (const proc of bundle.procedures) {
3839
+ procMap.set(proc.name, proc);
3840
+ }
3841
+ }
3842
+ }
3843
+ }
3844
+ if (this.options.procedures) {
3845
+ for (const proc of this.options.procedures) {
3846
+ procMap.set(proc.name, proc);
3847
+ }
3848
+ }
3849
+ return [...procMap.values()];
3850
+ }
2928
3851
  /**
2929
3852
  * Resolves template variables in rule content using project metadata.
2930
3853
  * Emits synthesis warnings for rules with unresolved variables.
@@ -2977,6 +3900,23 @@ ${extra}`
2977
3900
  return resolved !== agent.prompt ? { ...agent, prompt: resolved } : agent;
2978
3901
  });
2979
3902
  }
3903
+ /**
3904
+ * Resolves template variables in procedure content using project metadata.
3905
+ */
3906
+ resolveProcedureTemplates(procedures, metadata) {
3907
+ return procedures.map((proc) => {
3908
+ const { resolved, unresolvedKeys } = resolveTemplateVariables(
3909
+ proc.content,
3910
+ metadata
3911
+ );
3912
+ if (unresolvedKeys.length > 0) {
3913
+ this.project.logger.warn(
3914
+ `AgentConfig: ProjectMetadata not found; procedure '${proc.name}' using default values`
3915
+ );
3916
+ }
3917
+ return resolved !== proc.content ? { ...proc, content: resolved } : proc;
3918
+ });
3919
+ }
2980
3920
  /**
2981
3921
  * Collects Claude permission entries from all active bundles.
2982
3922
  */
@@ -4663,8 +5603,11 @@ export {
4663
5603
  getLatestEligibleVersion,
4664
5604
  githubWorkflowBundle,
4665
5605
  jestBundle,
5606
+ meetingAnalysisBundle,
5607
+ orchestratorBundle,
4666
5608
  pnpmBundle,
4667
5609
  projenBundle,
5610
+ resolveModelAlias,
4668
5611
  resolveTemplateVariables,
4669
5612
  slackBundle,
4670
5613
  turborepoBundle,