@codedrifters/configulator 0.0.183 → 0.0.185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.mts +34 -1
- package/lib/index.d.ts +35 -2
- package/lib/index.js +793 -3
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +792 -3
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -219,6 +219,7 @@ __export(index_exports, {
|
|
|
219
219
|
githubWorkflowBundle: () => githubWorkflowBundle,
|
|
220
220
|
jestBundle: () => jestBundle,
|
|
221
221
|
meetingAnalysisBundle: () => meetingAnalysisBundle,
|
|
222
|
+
orchestratorBundle: () => orchestratorBundle,
|
|
222
223
|
pnpmBundle: () => pnpmBundle,
|
|
223
224
|
projenBundle: () => projenBundle,
|
|
224
225
|
resolveModelAlias: () => resolveModelAlias,
|
|
@@ -1303,6 +1304,704 @@ var meetingAnalysisBundle = {
|
|
|
1303
1304
|
subAgents: [meetingAnalystSubAgent]
|
|
1304
1305
|
};
|
|
1305
1306
|
|
|
1307
|
+
// src/agent/bundles/orchestrator.ts
|
|
1308
|
+
var checkBlockedProcedure = {
|
|
1309
|
+
name: "check-blocked.sh",
|
|
1310
|
+
description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, prs",
|
|
1311
|
+
content: [
|
|
1312
|
+
"#!/usr/bin/env bash",
|
|
1313
|
+
"# check-blocked.sh \u2014 Token-efficient issue triage for agent loops.",
|
|
1314
|
+
"# Replaces inline body-parsing with shell pipelines that return only",
|
|
1315
|
+
"# actionable summaries.",
|
|
1316
|
+
"#",
|
|
1317
|
+
"# Usage:",
|
|
1318
|
+
"# .claude/procedures/check-blocked.sh unblock",
|
|
1319
|
+
"# .claude/procedures/check-blocked.sh eligible",
|
|
1320
|
+
"# .claude/procedures/check-blocked.sh stale",
|
|
1321
|
+
"# .claude/procedures/check-blocked.sh orphaned",
|
|
1322
|
+
"# .claude/procedures/check-blocked.sh prs",
|
|
1323
|
+
"",
|
|
1324
|
+
"set -uo pipefail",
|
|
1325
|
+
"",
|
|
1326
|
+
"# \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",
|
|
1327
|
+
"",
|
|
1328
|
+
"STALE_IN_PROGRESS_HOURS=72",
|
|
1329
|
+
"STALE_BLOCKED_HOURS=168",
|
|
1330
|
+
"",
|
|
1331
|
+
"# \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",
|
|
1332
|
+
"",
|
|
1333
|
+
'# Extract issue numbers from a "Depends on:" line.',
|
|
1334
|
+
'# Returns space-separated numbers, or empty string for "(none)".',
|
|
1335
|
+
"parse_deps() {",
|
|
1336
|
+
' local line="$1"',
|
|
1337
|
+
` if echo "$line" | grep -qi '(none)'; then`,
|
|
1338
|
+
' echo ""',
|
|
1339
|
+
" return",
|
|
1340
|
+
" fi",
|
|
1341
|
+
` echo "$line" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\n' ' ' || echo ""`,
|
|
1342
|
+
"}",
|
|
1343
|
+
"",
|
|
1344
|
+
"# Check if a single issue is closed. Returns 0 if closed, 1 if open.",
|
|
1345
|
+
"is_closed() {",
|
|
1346
|
+
" local state",
|
|
1347
|
+
` state=$(gh issue view "$1" --json state --jq '.state' 2>/dev/null || echo "UNKNOWN")`,
|
|
1348
|
+
' [[ "$state" == "CLOSED" ]]',
|
|
1349
|
+
"}",
|
|
1350
|
+
"",
|
|
1351
|
+
"# \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",
|
|
1352
|
+
"",
|
|
1353
|
+
"cmd_unblock() {",
|
|
1354
|
+
" local issues",
|
|
1355
|
+
' issues=$(gh issue list --label "status:blocked" --state open \\',
|
|
1356
|
+
' --json number,body --limit 50 2>/dev/null || echo "[]")',
|
|
1357
|
+
"",
|
|
1358
|
+
" local count",
|
|
1359
|
+
` count=$(echo "$issues" | jq 'length')`,
|
|
1360
|
+
' if [[ "$count" -eq 0 ]]; then',
|
|
1361
|
+
' echo "NO_BLOCKED_ISSUES"',
|
|
1362
|
+
" return 0",
|
|
1363
|
+
" fi",
|
|
1364
|
+
"",
|
|
1365
|
+
" local issue_data",
|
|
1366
|
+
` issue_data=$(echo "$issues" | jq -r '`,
|
|
1367
|
+
" .[] |",
|
|
1368
|
+
' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | .[0] // "") as $dep_line |',
|
|
1369
|
+
' "\\(.number)\\t\\($dep_line)"',
|
|
1370
|
+
" ')",
|
|
1371
|
+
"",
|
|
1372
|
+
" while IFS=$'\\t' read -r num dep_line; do",
|
|
1373
|
+
' [[ -z "$num" ]] && continue',
|
|
1374
|
+
"",
|
|
1375
|
+
' if [[ -z "$dep_line" ]]; then',
|
|
1376
|
+
' echo "BLOCKED #${num} \u2014 no Depends on field found"',
|
|
1377
|
+
" continue",
|
|
1378
|
+
" fi",
|
|
1379
|
+
"",
|
|
1380
|
+
" local deps",
|
|
1381
|
+
' deps=$(parse_deps "$dep_line")',
|
|
1382
|
+
' if [[ -z "${deps// /}" ]]; then',
|
|
1383
|
+
' echo "UNBLOCK #${num} \u2014 no dependencies"',
|
|
1384
|
+
" continue",
|
|
1385
|
+
" fi",
|
|
1386
|
+
"",
|
|
1387
|
+
" local all_closed=true",
|
|
1388
|
+
' local open_deps=""',
|
|
1389
|
+
' local closed_deps=""',
|
|
1390
|
+
" for dep in $deps; do",
|
|
1391
|
+
' if is_closed "$dep"; then',
|
|
1392
|
+
' closed_deps="${closed_deps}#${dep} "',
|
|
1393
|
+
" else",
|
|
1394
|
+
" all_closed=false",
|
|
1395
|
+
' open_deps="${open_deps}#${dep} "',
|
|
1396
|
+
" fi",
|
|
1397
|
+
" done",
|
|
1398
|
+
"",
|
|
1399
|
+
" if $all_closed; then",
|
|
1400
|
+
' echo "UNBLOCK #${num} \u2014 all deps closed (${closed_deps% })"',
|
|
1401
|
+
" else",
|
|
1402
|
+
' echo "BLOCKED #${num} \u2014 waiting on ${open_deps% }"',
|
|
1403
|
+
" fi",
|
|
1404
|
+
' done <<< "$issue_data"',
|
|
1405
|
+
"}",
|
|
1406
|
+
"",
|
|
1407
|
+
"cmd_eligible() {",
|
|
1408
|
+
" local issues",
|
|
1409
|
+
' issues=$(gh issue list --label "status:ready" --state open \\',
|
|
1410
|
+
' --search "sort:created-asc" \\',
|
|
1411
|
+
' --json number,title,body,labels --limit 50 2>/dev/null || echo "[]")',
|
|
1412
|
+
"",
|
|
1413
|
+
" local count",
|
|
1414
|
+
` count=$(echo "$issues" | jq 'length')`,
|
|
1415
|
+
' if [[ "$count" -eq 0 ]]; then',
|
|
1416
|
+
' echo "NO_READY_ISSUES"',
|
|
1417
|
+
" return 0",
|
|
1418
|
+
" fi",
|
|
1419
|
+
"",
|
|
1420
|
+
" local issue_data",
|
|
1421
|
+
` issue_data=$(echo "$issues" | jq -r '`,
|
|
1422
|
+
" .[] |",
|
|
1423
|
+
' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | .[0] // "") as $dep_line |',
|
|
1424
|
+
' (.labels | map(.name) | join(",")) as $label_str |',
|
|
1425
|
+
' (.labels | map(.name) | map(select(startswith("type:"))) | .[0] // "") as $type_label |',
|
|
1426
|
+
' "\\(.number)\\t\\(.title)\\t\\($dep_line)\\t\\($label_str)\\t\\($type_label)"',
|
|
1427
|
+
" ')",
|
|
1428
|
+
"",
|
|
1429
|
+
' local results=""',
|
|
1430
|
+
" while IFS=$'\\t' read -r num title dep_line labels_str type_label; do",
|
|
1431
|
+
' [[ -z "$num" ]] && continue',
|
|
1432
|
+
"",
|
|
1433
|
+
' local deps=""',
|
|
1434
|
+
' if [[ -n "$dep_line" ]]; then',
|
|
1435
|
+
' deps=$(parse_deps "$dep_line")',
|
|
1436
|
+
" fi",
|
|
1437
|
+
"",
|
|
1438
|
+
" # Check if any dep is still open.",
|
|
1439
|
+
" local has_open_dep=false",
|
|
1440
|
+
' local open_deps=""',
|
|
1441
|
+
' if [[ -n "${deps// /}" ]]; then',
|
|
1442
|
+
" for dep in $deps; do",
|
|
1443
|
+
' if ! is_closed "$dep"; then',
|
|
1444
|
+
" has_open_dep=true",
|
|
1445
|
+
' open_deps="${open_deps}#${dep} "',
|
|
1446
|
+
" fi",
|
|
1447
|
+
" done",
|
|
1448
|
+
" fi",
|
|
1449
|
+
"",
|
|
1450
|
+
" if $has_open_dep; then",
|
|
1451
|
+
' echo "SKIP #${num} \u2014 dep ${open_deps% } still open"',
|
|
1452
|
+
" continue",
|
|
1453
|
+
" fi",
|
|
1454
|
+
"",
|
|
1455
|
+
" # 5-level priority sort key.",
|
|
1456
|
+
" local sort_key=2",
|
|
1457
|
+
' local priority="medium"',
|
|
1458
|
+
' case "$labels_str" in',
|
|
1459
|
+
' *priority:critical*) sort_key=0; priority="critical" ;;',
|
|
1460
|
+
' *priority:high*) sort_key=1; priority="high" ;;',
|
|
1461
|
+
' *priority:medium*) sort_key=2; priority="medium" ;;',
|
|
1462
|
+
' *priority:low*) sort_key=3; priority="low" ;;',
|
|
1463
|
+
' *priority:trivial*) sort_key=4; priority="trivial" ;;',
|
|
1464
|
+
" esac",
|
|
1465
|
+
"",
|
|
1466
|
+
' local label_info=""',
|
|
1467
|
+
' [[ -n "$type_label" ]] && label_info=" ${type_label}"',
|
|
1468
|
+
"",
|
|
1469
|
+
' results="${results}${sort_key}\\t${num}\\tPICK #${num} priority:${priority}${label_info} \\"${title}\\"\\n"',
|
|
1470
|
+
' done <<< "$issue_data"',
|
|
1471
|
+
"",
|
|
1472
|
+
" # Sort by priority, then issue number (FIFO).",
|
|
1473
|
+
' if [[ -n "$results" ]]; then',
|
|
1474
|
+
` printf '%b' "$results" | sort -t$'\\t' -k1,1n -k2,2n | cut -f3`,
|
|
1475
|
+
" fi",
|
|
1476
|
+
"}",
|
|
1477
|
+
"",
|
|
1478
|
+
"cmd_stale() {",
|
|
1479
|
+
" # Check in-progress issues",
|
|
1480
|
+
" local ip_issues",
|
|
1481
|
+
' ip_issues=$(gh issue list --label "status:in-progress" --state open \\',
|
|
1482
|
+
' --json number,title,updatedAt --limit 50 2>/dev/null || echo "[]")',
|
|
1483
|
+
"",
|
|
1484
|
+
" local ip_count",
|
|
1485
|
+
` ip_count=$(echo "$ip_issues" | jq 'length')`,
|
|
1486
|
+
"",
|
|
1487
|
+
' if [[ "$ip_count" -gt 0 ]]; then',
|
|
1488
|
+
" local ip_threshold",
|
|
1489
|
+
" ip_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\",
|
|
1490
|
+
' || date -u -d "${STALE_IN_PROGRESS_HOURS} hours ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',
|
|
1491
|
+
"",
|
|
1492
|
+
" local ip_data",
|
|
1493
|
+
` ip_data=$(echo "$ip_issues" | jq -r '.[] | "\\(.number)\\t\\(.title)\\t\\(.updatedAt)"')`,
|
|
1494
|
+
"",
|
|
1495
|
+
" while IFS=$'\\t' read -r num title updated; do",
|
|
1496
|
+
' [[ -z "$num" ]] && continue',
|
|
1497
|
+
' local updated_trimmed="${updated%%+*}"',
|
|
1498
|
+
' updated_trimmed="${updated_trimmed%%Z*}"',
|
|
1499
|
+
' if [[ "$updated_trimmed" < "$ip_threshold" ]]; then',
|
|
1500
|
+
' local date_part="${updated_trimmed%%T*}"',
|
|
1501
|
+
' echo "STALE #${num} \u2014 no activity since ${date_part} \u2014 \\"${title}\\""',
|
|
1502
|
+
" fi",
|
|
1503
|
+
' done <<< "$ip_data"',
|
|
1504
|
+
" fi",
|
|
1505
|
+
"",
|
|
1506
|
+
" # Check blocked issues",
|
|
1507
|
+
" local bl_issues",
|
|
1508
|
+
' bl_issues=$(gh issue list --label "status:blocked" --state open \\',
|
|
1509
|
+
' --json number,title,updatedAt --limit 50 2>/dev/null || echo "[]")',
|
|
1510
|
+
"",
|
|
1511
|
+
" local bl_count",
|
|
1512
|
+
` bl_count=$(echo "$bl_issues" | jq 'length')`,
|
|
1513
|
+
"",
|
|
1514
|
+
' if [[ "$bl_count" -gt 0 ]]; then',
|
|
1515
|
+
" local bl_threshold",
|
|
1516
|
+
" bl_threshold=$(date -u -v-${STALE_BLOCKED_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\",
|
|
1517
|
+
' || date -u -d "${STALE_BLOCKED_HOURS} hours ago" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',
|
|
1518
|
+
"",
|
|
1519
|
+
" local bl_data",
|
|
1520
|
+
` bl_data=$(echo "$bl_issues" | jq -r '.[] | "\\(.number)\\t\\(.title)\\t\\(.updatedAt)"')`,
|
|
1521
|
+
"",
|
|
1522
|
+
" while IFS=$'\\t' read -r num title updated; do",
|
|
1523
|
+
' [[ -z "$num" ]] && continue',
|
|
1524
|
+
' local updated_trimmed="${updated%%+*}"',
|
|
1525
|
+
' updated_trimmed="${updated_trimmed%%Z*}"',
|
|
1526
|
+
' if [[ "$updated_trimmed" < "$bl_threshold" ]]; then',
|
|
1527
|
+
' local date_part="${updated_trimmed%%T*}"',
|
|
1528
|
+
' echo "STALE_BLOCKED #${num} \u2014 blocked since ${date_part} \u2014 \\"${title}\\""',
|
|
1529
|
+
" fi",
|
|
1530
|
+
' done <<< "$bl_data"',
|
|
1531
|
+
" fi",
|
|
1532
|
+
"",
|
|
1533
|
+
' if [[ "$ip_count" -eq 0 && "$bl_count" -eq 0 ]]; then',
|
|
1534
|
+
' echo "NO_STALE_ISSUES"',
|
|
1535
|
+
" fi",
|
|
1536
|
+
"}",
|
|
1537
|
+
"",
|
|
1538
|
+
"cmd_orphaned() {",
|
|
1539
|
+
" # Check for remote branches whose issues are closed or missing",
|
|
1540
|
+
" git fetch --prune origin 2>/dev/null",
|
|
1541
|
+
" local branches",
|
|
1542
|
+
' branches=$(git branch -r --format="%(refname:short)" | grep -v HEAD | sed "s|origin/||")',
|
|
1543
|
+
"",
|
|
1544
|
+
" local found_orphan=false",
|
|
1545
|
+
" while IFS= read -r branch; do",
|
|
1546
|
+
' [[ -z "$branch" ]] && continue',
|
|
1547
|
+
' [[ "$branch" == "main" || "$branch" == "master" ]] && continue',
|
|
1548
|
+
"",
|
|
1549
|
+
" # Extract issue number from branch name (e.g., feat/42-add-login \u2192 42)",
|
|
1550
|
+
" local issue_num",
|
|
1551
|
+
` issue_num=$(echo "$branch" | grep -oE '/[0-9]+' | tr -d '/' | head -1)`,
|
|
1552
|
+
' [[ -z "$issue_num" ]] && continue',
|
|
1553
|
+
"",
|
|
1554
|
+
" local state",
|
|
1555
|
+
` state=$(gh issue view "$issue_num" --json state --jq '.state' 2>/dev/null || echo "NOT_FOUND")`,
|
|
1556
|
+
"",
|
|
1557
|
+
' if [[ "$state" == "CLOSED" ]]; then',
|
|
1558
|
+
" found_orphan=true",
|
|
1559
|
+
' echo "ORPHAN_BRANCH ${branch} \u2014 issue #${issue_num} is closed"',
|
|
1560
|
+
' elif [[ "$state" == "NOT_FOUND" ]]; then',
|
|
1561
|
+
" found_orphan=true",
|
|
1562
|
+
' echo "ORPHAN_BRANCH ${branch} \u2014 issue #${issue_num} not found"',
|
|
1563
|
+
" fi",
|
|
1564
|
+
' done <<< "$branches"',
|
|
1565
|
+
"",
|
|
1566
|
+
" # Check for open PRs whose linked issues are closed",
|
|
1567
|
+
" local prs",
|
|
1568
|
+
' prs=$(gh pr list --state open --json number,title,body --limit 50 2>/dev/null || echo "[]")',
|
|
1569
|
+
" local pr_data",
|
|
1570
|
+
` pr_data=$(echo "$prs" | jq -r '`,
|
|
1571
|
+
" .[] |",
|
|
1572
|
+
' (.body | capture("(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)") | .num) as $issue |',
|
|
1573
|
+
' "\\(.number)\\t\\(.title)\\t\\($issue // "")"',
|
|
1574
|
+
" ' 2>/dev/null)",
|
|
1575
|
+
"",
|
|
1576
|
+
" while IFS=$'\\t' read -r pr_num title issue_num; do",
|
|
1577
|
+
' [[ -z "$pr_num" || -z "$issue_num" ]] && continue',
|
|
1578
|
+
' if is_closed "$issue_num"; then',
|
|
1579
|
+
" found_orphan=true",
|
|
1580
|
+
' echo "ORPHAN_PR #${pr_num} \u2014 linked issue #${issue_num} is closed \u2014 \\"${title}\\""',
|
|
1581
|
+
" fi",
|
|
1582
|
+
' done <<< "$pr_data"',
|
|
1583
|
+
"",
|
|
1584
|
+
" if ! $found_orphan; then",
|
|
1585
|
+
' echo "NO_ORPHANED_RESOURCES"',
|
|
1586
|
+
" fi",
|
|
1587
|
+
"}",
|
|
1588
|
+
"",
|
|
1589
|
+
"cmd_prs() {",
|
|
1590
|
+
" local prs",
|
|
1591
|
+
" prs=$(gh pr list --state open --json number,title,isDraft,headRefName,labels,body \\",
|
|
1592
|
+
' --limit 50 2>/dev/null || echo "[]")',
|
|
1593
|
+
"",
|
|
1594
|
+
" local count",
|
|
1595
|
+
` count=$(echo "$prs" | jq 'length')`,
|
|
1596
|
+
' if [[ "$count" -eq 0 ]]; then',
|
|
1597
|
+
' echo "NO_OPEN_PRS"',
|
|
1598
|
+
" return 0",
|
|
1599
|
+
" fi",
|
|
1600
|
+
"",
|
|
1601
|
+
" # Filter: not draft, no needs-attention label.",
|
|
1602
|
+
" local eligible",
|
|
1603
|
+
` eligible=$(echo "$prs" | jq -r '`,
|
|
1604
|
+
" .[] |",
|
|
1605
|
+
" select(.isDraft == false) |",
|
|
1606
|
+
' select(.labels | map(.name) | index("status:needs-attention") | not) |',
|
|
1607
|
+
' (.body | capture("(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)") | .num) as $issue |',
|
|
1608
|
+
' "\\(.number)\\t\\(.title)\\t\\(.headRefName)\\t\\($issue // "")"',
|
|
1609
|
+
" ' 2>/dev/null)",
|
|
1610
|
+
"",
|
|
1611
|
+
' if [[ -z "$eligible" ]]; then',
|
|
1612
|
+
' echo "NO_ELIGIBLE_PRS"',
|
|
1613
|
+
" return 0",
|
|
1614
|
+
" fi",
|
|
1615
|
+
"",
|
|
1616
|
+
" while IFS=$'\\t' read -r pr_num title branch issue_num; do",
|
|
1617
|
+
' [[ -z "$pr_num" ]] && continue',
|
|
1618
|
+
"",
|
|
1619
|
+
' if [[ -z "$issue_num" ]]; then',
|
|
1620
|
+
' echo "SKIP PR #${pr_num} \u2014 no linked issue \u2014 \\"${title}\\""',
|
|
1621
|
+
" continue",
|
|
1622
|
+
" fi",
|
|
1623
|
+
"",
|
|
1624
|
+
" # Check CI status",
|
|
1625
|
+
" local failing_checks",
|
|
1626
|
+
' failing_checks=$(gh pr checks "$pr_num" --json name,state \\',
|
|
1627
|
+
` --jq '[.[] | select(.state != "SUCCESS" and .state != "SKIPPED")] | length' 2>/dev/null || echo "-1")`,
|
|
1628
|
+
"",
|
|
1629
|
+
' if [[ "$failing_checks" == "-1" ]]; then',
|
|
1630
|
+
' echo "SKIP PR #${pr_num} \u2014 could not read CI status \u2014 \\"${title}\\""',
|
|
1631
|
+
" continue",
|
|
1632
|
+
" fi",
|
|
1633
|
+
"",
|
|
1634
|
+
' if [[ "$failing_checks" -gt 0 ]]; then',
|
|
1635
|
+
' echo "SKIP PR #${pr_num} \u2014 ${failing_checks} CI check(s) not passing \u2014 \\"${title}\\""',
|
|
1636
|
+
" continue",
|
|
1637
|
+
" fi",
|
|
1638
|
+
"",
|
|
1639
|
+
" # Check if already approved",
|
|
1640
|
+
" local approved",
|
|
1641
|
+
' approved=$(gh pr view "$pr_num" --json reviews \\',
|
|
1642
|
+
` --jq '[.reviews[] | select(.state == "APPROVED")] | length' 2>/dev/null || echo "0")`,
|
|
1643
|
+
' if [[ "$approved" -gt 0 ]]; then',
|
|
1644
|
+
' echo "SKIP PR #${pr_num} \u2014 already approved \u2014 \\"${title}\\""',
|
|
1645
|
+
" continue",
|
|
1646
|
+
" fi",
|
|
1647
|
+
"",
|
|
1648
|
+
' echo "REVIEW PR #${pr_num} issue:#${issue_num} branch:${branch} \u2014 \\"${title}\\""',
|
|
1649
|
+
' done <<< "$eligible"',
|
|
1650
|
+
"}",
|
|
1651
|
+
"",
|
|
1652
|
+
"# \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",
|
|
1653
|
+
"",
|
|
1654
|
+
'case "${1:-help}" in',
|
|
1655
|
+
' unblock) shift; cmd_unblock "$@" ;;',
|
|
1656
|
+
' eligible) shift; cmd_eligible "$@" ;;',
|
|
1657
|
+
' stale) shift; cmd_stale "$@" ;;',
|
|
1658
|
+
' orphaned) shift; cmd_orphaned "$@" ;;',
|
|
1659
|
+
' prs) shift; cmd_prs "$@" ;;',
|
|
1660
|
+
" help|*)",
|
|
1661
|
+
' echo "Usage: check-blocked.sh <unblock|eligible|stale|orphaned|prs>"',
|
|
1662
|
+
" exit 1",
|
|
1663
|
+
" ;;",
|
|
1664
|
+
"esac"
|
|
1665
|
+
].join("\n")
|
|
1666
|
+
};
|
|
1667
|
+
var orchestratorSubAgent = {
|
|
1668
|
+
name: "orchestrator",
|
|
1669
|
+
description: "Pipeline manager that reviews PRs, triages issues, and identifies the next work item \u2014 never implements code",
|
|
1670
|
+
model: AGENT_MODEL.POWERFUL,
|
|
1671
|
+
maxTurns: 100,
|
|
1672
|
+
platforms: { cursor: { exclude: true } },
|
|
1673
|
+
prompt: [
|
|
1674
|
+
"# Orchestrator Agent",
|
|
1675
|
+
"",
|
|
1676
|
+
"You are a pipeline manager for the **{{repository.owner}}/{{repository.name}}** repository.",
|
|
1677
|
+
"You review PRs, triage issues, and identify the next work item. You **never**",
|
|
1678
|
+
"implement code, create branches for issues, or claim issues.",
|
|
1679
|
+
"",
|
|
1680
|
+
"Run the same loop every invocation. Execute all phases in order.",
|
|
1681
|
+
"",
|
|
1682
|
+
"---",
|
|
1683
|
+
"",
|
|
1684
|
+
"## Phase A: Startup",
|
|
1685
|
+
"",
|
|
1686
|
+
"```bash",
|
|
1687
|
+
"git checkout main && git pull origin main",
|
|
1688
|
+
"```",
|
|
1689
|
+
"",
|
|
1690
|
+
"## Phase B: Batch PR Review",
|
|
1691
|
+
"",
|
|
1692
|
+
"Find all PRs eligible for review:",
|
|
1693
|
+
"",
|
|
1694
|
+
"```bash",
|
|
1695
|
+
".claude/procedures/check-blocked.sh prs",
|
|
1696
|
+
"```",
|
|
1697
|
+
"",
|
|
1698
|
+
"For each `REVIEW PR #N issue:#M branch:<branch>` line:",
|
|
1699
|
+
"",
|
|
1700
|
+
"1. Check out the PR branch: `gh pr checkout N`",
|
|
1701
|
+
"2. Review the PR:",
|
|
1702
|
+
" - Read the PR description and linked issue: `gh pr view N`",
|
|
1703
|
+
" - Review the diff: `gh pr diff N`",
|
|
1704
|
+
" - Check all changed files for correctness, conventions, and test coverage",
|
|
1705
|
+
" - Verify PR conventions: conventional commit title, closing keyword, summary present",
|
|
1706
|
+
" - Check CI status: `gh pr checks N`",
|
|
1707
|
+
"3. If the PR passes review:",
|
|
1708
|
+
" - Approve: `gh pr review N --approve --body '<summary>'`",
|
|
1709
|
+
" - Enable auto-merge: `gh pr merge N --auto --squash`",
|
|
1710
|
+
"4. If the PR fails review:",
|
|
1711
|
+
" - Request changes: `gh pr review N --request-changes --body '<findings>'`",
|
|
1712
|
+
"5. After each PR (whether merged or not):",
|
|
1713
|
+
" ```bash",
|
|
1714
|
+
" git checkout main && git pull origin main",
|
|
1715
|
+
" ```",
|
|
1716
|
+
"",
|
|
1717
|
+
"Skip lines starting with `SKIP` \u2014 those PRs are not eligible.",
|
|
1718
|
+
"If output is `NO_OPEN_PRS` or `NO_ELIGIBLE_PRS`, skip to Phase C.",
|
|
1719
|
+
"",
|
|
1720
|
+
"## Phase C: Triage \u2014 Unblock",
|
|
1721
|
+
"",
|
|
1722
|
+
"Check for blocked issues whose dependencies have resolved:",
|
|
1723
|
+
"",
|
|
1724
|
+
"```bash",
|
|
1725
|
+
".claude/procedures/check-blocked.sh unblock",
|
|
1726
|
+
"```",
|
|
1727
|
+
"",
|
|
1728
|
+
"For each `UNBLOCK #N` line:",
|
|
1729
|
+
"```bash",
|
|
1730
|
+
'gh issue edit N --remove-label "status:blocked" --add-label "status:ready"',
|
|
1731
|
+
'gh issue comment N --body "Dependencies resolved \u2014 unblocking."',
|
|
1732
|
+
"```",
|
|
1733
|
+
"",
|
|
1734
|
+
"For `BLOCKED #N \u2014 no Depends on field found`: leave as-is (Phase D will",
|
|
1735
|
+
"catch it if it's been blocked too long).",
|
|
1736
|
+
"",
|
|
1737
|
+
"If output is `NO_BLOCKED_ISSUES`, skip to Phase D.",
|
|
1738
|
+
"",
|
|
1739
|
+
"## Phase D: Maintenance",
|
|
1740
|
+
"",
|
|
1741
|
+
"### D1: Stale Detection",
|
|
1742
|
+
"",
|
|
1743
|
+
"```bash",
|
|
1744
|
+
".claude/procedures/check-blocked.sh stale",
|
|
1745
|
+
"```",
|
|
1746
|
+
"",
|
|
1747
|
+
"For each `STALE #N` line (in-progress >72h without activity):",
|
|
1748
|
+
"```bash",
|
|
1749
|
+
'gh issue edit N --add-label "status:needs-attention"',
|
|
1750
|
+
'gh issue comment N --body "Flagged: in-progress for >3 days with no activity."',
|
|
1751
|
+
"```",
|
|
1752
|
+
"",
|
|
1753
|
+
"For each `STALE_BLOCKED #N` line (blocked >168h):",
|
|
1754
|
+
"```bash",
|
|
1755
|
+
'gh issue edit N --add-label "status:needs-attention"',
|
|
1756
|
+
'gh issue comment N --body "Flagged: blocked for >7 days \u2014 may need human intervention."',
|
|
1757
|
+
"```",
|
|
1758
|
+
"",
|
|
1759
|
+
"**Important:** Do NOT auto-reset stale issues to `status:ready` \u2014 partial",
|
|
1760
|
+
"implementation work may exist on a branch.",
|
|
1761
|
+
"",
|
|
1762
|
+
"### D2: Orphaned Detection",
|
|
1763
|
+
"",
|
|
1764
|
+
"```bash",
|
|
1765
|
+
".claude/procedures/check-blocked.sh orphaned",
|
|
1766
|
+
"```",
|
|
1767
|
+
"",
|
|
1768
|
+
"Report any `ORPHAN_BRANCH` or `ORPHAN_PR` lines. These indicate branches",
|
|
1769
|
+
"or PRs whose linked issues are closed or missing. Log them for visibility",
|
|
1770
|
+
"but do not delete branches automatically.",
|
|
1771
|
+
"",
|
|
1772
|
+
"### D3: Needs-Attention Summary",
|
|
1773
|
+
"",
|
|
1774
|
+
"List all issues currently flagged:",
|
|
1775
|
+
"```bash",
|
|
1776
|
+
'gh issue list --label "status:needs-attention" --state open --json number,title',
|
|
1777
|
+
"```",
|
|
1778
|
+
"",
|
|
1779
|
+
"Log the count and titles for operator visibility.",
|
|
1780
|
+
"",
|
|
1781
|
+
"## Phase E: Queue Scan",
|
|
1782
|
+
"",
|
|
1783
|
+
"Find the highest-priority ready issue:",
|
|
1784
|
+
"",
|
|
1785
|
+
"```bash",
|
|
1786
|
+
".claude/procedures/check-blocked.sh eligible",
|
|
1787
|
+
"```",
|
|
1788
|
+
"",
|
|
1789
|
+
"If a `PICK` line is returned, report it as:",
|
|
1790
|
+
"```",
|
|
1791
|
+
'NEXT_WORK_ITEM #<number> priority:<level> type:<label> "<title>"',
|
|
1792
|
+
"```",
|
|
1793
|
+
"",
|
|
1794
|
+
"If output is `NO_READY_ISSUES`, report that the queue is empty.",
|
|
1795
|
+
"",
|
|
1796
|
+
"**Do NOT claim the issue, create a branch, or start implementation.**",
|
|
1797
|
+
"The worker agent handles that.",
|
|
1798
|
+
"",
|
|
1799
|
+
"## Phase F: Cleanup",
|
|
1800
|
+
"",
|
|
1801
|
+
"```bash",
|
|
1802
|
+
"git checkout main && git pull origin main",
|
|
1803
|
+
"git fetch --prune origin",
|
|
1804
|
+
"```",
|
|
1805
|
+
"",
|
|
1806
|
+
"Log completion: phases executed, PRs reviewed, issues unblocked,",
|
|
1807
|
+
"stale issues flagged, and next work item (if any).",
|
|
1808
|
+
"",
|
|
1809
|
+
"---",
|
|
1810
|
+
"",
|
|
1811
|
+
"## Rules",
|
|
1812
|
+
"",
|
|
1813
|
+
"1. **Never implement code.** You triage, review, and report \u2014 you do not code.",
|
|
1814
|
+
"2. **Never claim issues.** Do not add `status:in-progress` or create branches for issues.",
|
|
1815
|
+
"3. **Always use check-blocked.sh.** All triage queries go through the shell script for token efficiency.",
|
|
1816
|
+
"4. **Follow CLAUDE.md conventions** for all git and gh operations.",
|
|
1817
|
+
"5. **Priority order:** critical > high > medium > low > trivial, then FIFO by issue number."
|
|
1818
|
+
].join("\n")
|
|
1819
|
+
};
|
|
1820
|
+
var issueWorkerSubAgent = {
|
|
1821
|
+
name: "issue-worker",
|
|
1822
|
+
description: "Selects the next ready issue from the queue, claims it, and implements the change end-to-end following repository conventions",
|
|
1823
|
+
model: AGENT_MODEL.POWERFUL,
|
|
1824
|
+
maxTurns: 50,
|
|
1825
|
+
canDelegateToAgents: [],
|
|
1826
|
+
platforms: { cursor: { exclude: true } },
|
|
1827
|
+
prompt: [
|
|
1828
|
+
"# Issue Worker",
|
|
1829
|
+
"",
|
|
1830
|
+
"You are the issue worker for **{{repository.owner}}/{{repository.name}}**.",
|
|
1831
|
+
"Your job is to pick the next issue from the queue, claim it, and implement",
|
|
1832
|
+
"the change end-to-end \u2014 from branch creation through to opening a PR.",
|
|
1833
|
+
"",
|
|
1834
|
+
"---",
|
|
1835
|
+
"",
|
|
1836
|
+
"## Phase 1: Select an Issue",
|
|
1837
|
+
"",
|
|
1838
|
+
"If an issue number was provided in your instructions, use that issue.",
|
|
1839
|
+
"Otherwise, find the next issue to work on:",
|
|
1840
|
+
"",
|
|
1841
|
+
"```bash",
|
|
1842
|
+
".claude/procedures/check-blocked.sh eligible",
|
|
1843
|
+
"```",
|
|
1844
|
+
"",
|
|
1845
|
+
"This returns issues sorted by priority (critical > high > medium > low > trivial),",
|
|
1846
|
+
"then by issue number (FIFO). Take the **first** `PICK` line.",
|
|
1847
|
+
"",
|
|
1848
|
+
"If the output is `NO_READY_ISSUES`, report that the queue is empty and stop.",
|
|
1849
|
+
"",
|
|
1850
|
+
"If any `SKIP` lines appear, ignore them \u2014 those issues have unresolved dependencies.",
|
|
1851
|
+
"",
|
|
1852
|
+
"## Phase 2: Claim the Issue",
|
|
1853
|
+
"",
|
|
1854
|
+
"```bash",
|
|
1855
|
+
'gh issue edit <number> --remove-label "status:ready" --add-label "status:in-progress"',
|
|
1856
|
+
"```",
|
|
1857
|
+
"",
|
|
1858
|
+
"Read the full issue details:",
|
|
1859
|
+
"```bash",
|
|
1860
|
+
"gh issue view <number>",
|
|
1861
|
+
"```",
|
|
1862
|
+
"",
|
|
1863
|
+
"## Phase 3: Set Up",
|
|
1864
|
+
"",
|
|
1865
|
+
"```bash",
|
|
1866
|
+
"git checkout {{repository.defaultBranch}} && git pull origin {{repository.defaultBranch}}",
|
|
1867
|
+
"```",
|
|
1868
|
+
"",
|
|
1869
|
+
"Determine the branch type from the issue's `type:*` label or title prefix:",
|
|
1870
|
+
"",
|
|
1871
|
+
"| Label / prefix | Branch type |",
|
|
1872
|
+
"|---------------|-------------|",
|
|
1873
|
+
"| `type:feat` / `feat:` | `feat/` |",
|
|
1874
|
+
"| `type:fix` / `fix:` | `fix/` |",
|
|
1875
|
+
"| `type:chore` / `chore:` | `chore/` |",
|
|
1876
|
+
"| `type:refactor` / `refactor:` | `refactor/` |",
|
|
1877
|
+
"| `type:docs` / `docs:` | `docs/` |",
|
|
1878
|
+
"| `type:release` / `release:` | `release/` |",
|
|
1879
|
+
"| `type:hotfix` / `hotfix:` | `hotfix/` |",
|
|
1880
|
+
"| No type label | `feat/` (default) |",
|
|
1881
|
+
"",
|
|
1882
|
+
"Create a branch following the naming convention:",
|
|
1883
|
+
"```bash",
|
|
1884
|
+
"git checkout -b <type>/<issue-number>-<slug>",
|
|
1885
|
+
"```",
|
|
1886
|
+
"",
|
|
1887
|
+
"The slug should be a short (3-5 word) kebab-case summary derived from the issue title.",
|
|
1888
|
+
"",
|
|
1889
|
+
"Link the branch to the issue:",
|
|
1890
|
+
"```bash",
|
|
1891
|
+
"gh issue comment <number> --body 'Branch: `<branch-name>`'",
|
|
1892
|
+
"```",
|
|
1893
|
+
"",
|
|
1894
|
+
"## Phase 4: Implement",
|
|
1895
|
+
"",
|
|
1896
|
+
"Read the issue body carefully. Understand the acceptance criteria.",
|
|
1897
|
+
"",
|
|
1898
|
+
"Implement the change following these guidelines based on issue type:",
|
|
1899
|
+
"",
|
|
1900
|
+
"- **feat**: Implement the new feature. Add tests. Export public APIs from `index.ts`.",
|
|
1901
|
+
"- **fix**: Reproduce the bug first. Write a failing test. Fix the bug. Verify the test passes.",
|
|
1902
|
+
"- **chore**: Make the maintenance change. Verify no regressions.",
|
|
1903
|
+
"- **refactor**: Restructure code without changing behavior. Existing tests must pass unchanged.",
|
|
1904
|
+
"- **docs**: Update documentation only. Do not change source code.",
|
|
1905
|
+
"",
|
|
1906
|
+
"Follow all conventions from CLAUDE.md and the project's agent rules.",
|
|
1907
|
+
"",
|
|
1908
|
+
"## Phase 5: Verify",
|
|
1909
|
+
"",
|
|
1910
|
+
"Run the appropriate verification commands depending on what changed:",
|
|
1911
|
+
"",
|
|
1912
|
+
"1. If Projen config was changed: `npx projen && pnpm install`",
|
|
1913
|
+
"2. Compile the affected package: `pnpm --filter @codedrifters/<package> compile`",
|
|
1914
|
+
"3. Test the affected package: `pnpm --filter @codedrifters/<package> test`",
|
|
1915
|
+
"4. If changes span multiple packages: `pnpm build:all`",
|
|
1916
|
+
"",
|
|
1917
|
+
"Fix any compilation errors, test failures, or lint errors before proceeding.",
|
|
1918
|
+
"",
|
|
1919
|
+
"## Phase 6: Commit and Push",
|
|
1920
|
+
"",
|
|
1921
|
+
"Use conventional commit messages:",
|
|
1922
|
+
"```bash",
|
|
1923
|
+
"git add <files>",
|
|
1924
|
+
'git commit -m "<type>: <description>"',
|
|
1925
|
+
"git push -u origin <branch-name>",
|
|
1926
|
+
"```",
|
|
1927
|
+
"",
|
|
1928
|
+
"## Phase 7: Open a PR",
|
|
1929
|
+
"",
|
|
1930
|
+
"```bash",
|
|
1931
|
+
'gh pr create --title "<type>(<scope>): <description>" --body "## Summary',
|
|
1932
|
+
"",
|
|
1933
|
+
"<bullet points>",
|
|
1934
|
+
"",
|
|
1935
|
+
'Closes #<issue-number>"',
|
|
1936
|
+
"```",
|
|
1937
|
+
"",
|
|
1938
|
+
"Enable auto-merge:",
|
|
1939
|
+
"```bash",
|
|
1940
|
+
"gh pr merge --auto --squash",
|
|
1941
|
+
"```",
|
|
1942
|
+
"",
|
|
1943
|
+
"## Phase 8: Update Status",
|
|
1944
|
+
"",
|
|
1945
|
+
"After the PR is created:",
|
|
1946
|
+
"```bash",
|
|
1947
|
+
'gh issue edit <number> --add-label "status:done"',
|
|
1948
|
+
"```",
|
|
1949
|
+
"",
|
|
1950
|
+
"---",
|
|
1951
|
+
"",
|
|
1952
|
+
"## Rules",
|
|
1953
|
+
"",
|
|
1954
|
+
"1. **One issue per session.** Process exactly ONE issue, then stop.",
|
|
1955
|
+
"2. **Use check-blocked.sh.** Always use the procedure script for issue selection.",
|
|
1956
|
+
"3. **Follow CLAUDE.md conventions** for branch naming, commits, and PRs.",
|
|
1957
|
+
"4. **Do not assign PRs to a project board** \u2014 this repo has no GitHub project.",
|
|
1958
|
+
"5. **Do not add AI co-author** attribution to commits.",
|
|
1959
|
+
"6. **On failure:** If you cannot complete the issue, update labels and leave a comment:",
|
|
1960
|
+
" ```bash",
|
|
1961
|
+
' gh issue edit <number> --remove-label "status:in-progress" --add-label "status:needs-attention"',
|
|
1962
|
+
' gh issue comment <number> --body "Worker could not complete: <reason>"',
|
|
1963
|
+
" ```"
|
|
1964
|
+
].join("\n")
|
|
1965
|
+
};
|
|
1966
|
+
var orchestratorBundle = {
|
|
1967
|
+
name: "orchestrator",
|
|
1968
|
+
description: "Pipeline orchestrator agent for issue triage, PR review, and queue management",
|
|
1969
|
+
// Always included by default
|
|
1970
|
+
appliesWhen: () => true,
|
|
1971
|
+
rules: [
|
|
1972
|
+
{
|
|
1973
|
+
name: "orchestrator-conventions",
|
|
1974
|
+
description: "Guidelines for orchestrator agent behavior and pipeline management",
|
|
1975
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
1976
|
+
content: [
|
|
1977
|
+
"# Orchestrator Conventions",
|
|
1978
|
+
"",
|
|
1979
|
+
"When running the orchestrator agent (`.claude/agents/orchestrator.md`):",
|
|
1980
|
+
"",
|
|
1981
|
+
"- The orchestrator **never** implements code or creates branches for issues",
|
|
1982
|
+
"- It reviews PRs, triages issues, and reports the next work item",
|
|
1983
|
+
"- All triage queries use `.claude/procedures/check-blocked.sh` for token efficiency",
|
|
1984
|
+
"- Priority order: critical > high > medium > low > trivial, then FIFO",
|
|
1985
|
+
"- Stale thresholds: 72h for in-progress, 168h for blocked",
|
|
1986
|
+
"- Flagged issues get `status:needs-attention` \u2014 they are not auto-reset"
|
|
1987
|
+
].join("\n"),
|
|
1988
|
+
platforms: {
|
|
1989
|
+
claude: { target: "claude-md" },
|
|
1990
|
+
cursor: { exclude: true }
|
|
1991
|
+
},
|
|
1992
|
+
tags: ["workflow"]
|
|
1993
|
+
}
|
|
1994
|
+
],
|
|
1995
|
+
subAgents: [orchestratorSubAgent, issueWorkerSubAgent],
|
|
1996
|
+
procedures: [checkBlockedProcedure],
|
|
1997
|
+
claudePermissions: {
|
|
1998
|
+
allow: [
|
|
1999
|
+
// Allow executing the check-blocked.sh procedure
|
|
2000
|
+
"Bash(.claude/procedures/*.sh *)"
|
|
2001
|
+
]
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
|
|
1306
2005
|
// src/pnpm/pnpm-workspace.ts
|
|
1307
2006
|
var import_path = require("path");
|
|
1308
2007
|
var import_projen = require("projen");
|
|
@@ -2320,7 +3019,8 @@ var BUILT_IN_BUNDLES = [
|
|
|
2320
3019
|
projenBundle,
|
|
2321
3020
|
githubWorkflowBundle,
|
|
2322
3021
|
slackBundle,
|
|
2323
|
-
meetingAnalysisBundle
|
|
3022
|
+
meetingAnalysisBundle,
|
|
3023
|
+
orchestratorBundle
|
|
2324
3024
|
];
|
|
2325
3025
|
|
|
2326
3026
|
// src/agent/bundles/scope.ts
|
|
@@ -2443,12 +3143,15 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
2443
3143
|
/**
|
|
2444
3144
|
* Render all Claude Code configuration files.
|
|
2445
3145
|
*/
|
|
2446
|
-
static render(component, rules, skills, subAgents, mcpServers, settings) {
|
|
3146
|
+
static render(component, rules, skills, subAgents, mcpServers, settings, procedures) {
|
|
2447
3147
|
_ClaudeRenderer.renderClaudeMd(component, rules);
|
|
2448
3148
|
_ClaudeRenderer.renderScopedRules(component, rules);
|
|
2449
3149
|
_ClaudeRenderer.renderSettings(component, mcpServers, settings);
|
|
2450
3150
|
_ClaudeRenderer.renderSkills(component, skills);
|
|
2451
3151
|
_ClaudeRenderer.renderSubAgents(component, subAgents);
|
|
3152
|
+
if (procedures && procedures.length > 0) {
|
|
3153
|
+
_ClaudeRenderer.renderProcedures(component, procedures);
|
|
3154
|
+
}
|
|
2452
3155
|
}
|
|
2453
3156
|
static renderClaudeMd(component, rules) {
|
|
2454
3157
|
const claudeMdRules = rules.filter((r) => {
|
|
@@ -2747,6 +3450,12 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
2747
3450
|
if (agent.platforms?.claude?.memory) {
|
|
2748
3451
|
lines.push(`memory: ${agent.platforms.claude.memory}`);
|
|
2749
3452
|
}
|
|
3453
|
+
if (agent.canDelegateToAgents && agent.canDelegateToAgents.length > 0) {
|
|
3454
|
+
lines.push(`canDelegateToAgents:`);
|
|
3455
|
+
for (const delegateName of agent.canDelegateToAgents) {
|
|
3456
|
+
lines.push(` - "${delegateName}"`);
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
2750
3459
|
lines.push("---");
|
|
2751
3460
|
lines.push("");
|
|
2752
3461
|
lines.push(...agent.prompt.split("\n"));
|
|
@@ -2765,6 +3474,14 @@ var ClaudeRenderer = class _ClaudeRenderer {
|
|
|
2765
3474
|
if (config.env) server.env = { ...config.env };
|
|
2766
3475
|
return server;
|
|
2767
3476
|
}
|
|
3477
|
+
static renderProcedures(component, procedures) {
|
|
3478
|
+
for (const proc of procedures) {
|
|
3479
|
+
new import_textfile2.TextFile(component, `.claude/procedures/${proc.name}`, {
|
|
3480
|
+
lines: proc.content.split("\n"),
|
|
3481
|
+
executable: true
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
2768
3485
|
/**
|
|
2769
3486
|
* Determine the default Claude rule target based on rule scope.
|
|
2770
3487
|
* ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.
|
|
@@ -3118,6 +3835,7 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
|
|
|
3118
3835
|
const rules = this.resolveRules();
|
|
3119
3836
|
const skills = this.resolveSkills();
|
|
3120
3837
|
const subAgents = this.resolveSubAgents();
|
|
3838
|
+
const procedures = this.resolveProcedures();
|
|
3121
3839
|
const mcpServers = this.options.mcpServers ?? {};
|
|
3122
3840
|
const projectMetadata = ProjectMetadata.of(this.project);
|
|
3123
3841
|
const metadata = projectMetadata?.metadata;
|
|
@@ -3127,6 +3845,10 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
|
|
|
3127
3845
|
subAgents,
|
|
3128
3846
|
metadata
|
|
3129
3847
|
);
|
|
3848
|
+
const resolvedProcedures = this.resolveProcedureTemplates(
|
|
3849
|
+
procedures,
|
|
3850
|
+
metadata
|
|
3851
|
+
);
|
|
3130
3852
|
if (platforms.includes(AGENT_PLATFORM.CURSOR)) {
|
|
3131
3853
|
CursorRenderer.render(
|
|
3132
3854
|
this,
|
|
@@ -3148,7 +3870,8 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
|
|
|
3148
3870
|
_AgentConfig.mergeClaudeDefaults(
|
|
3149
3871
|
this.options.claudeSettings,
|
|
3150
3872
|
bundlePermissions
|
|
3151
|
-
)
|
|
3873
|
+
),
|
|
3874
|
+
resolvedProcedures
|
|
3152
3875
|
);
|
|
3153
3876
|
}
|
|
3154
3877
|
if (platforms.includes(AGENT_PLATFORM.CODEX)) {
|
|
@@ -3261,6 +3984,16 @@ ${extra}`
|
|
|
3261
3984
|
}
|
|
3262
3985
|
}
|
|
3263
3986
|
}
|
|
3987
|
+
if (this.options.includeBundles) {
|
|
3988
|
+
for (const bundleName of this.options.includeBundles) {
|
|
3989
|
+
const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
|
|
3990
|
+
if (bundle?.skills) {
|
|
3991
|
+
for (const skill of bundle.skills) {
|
|
3992
|
+
skillMap.set(skill.name, skill);
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3264
3997
|
if (this.options.skills) {
|
|
3265
3998
|
for (const skill of this.options.skills) {
|
|
3266
3999
|
skillMap.set(skill.name, skill);
|
|
@@ -3280,6 +4013,16 @@ ${extra}`
|
|
|
3280
4013
|
}
|
|
3281
4014
|
}
|
|
3282
4015
|
}
|
|
4016
|
+
if (this.options.includeBundles) {
|
|
4017
|
+
for (const bundleName of this.options.includeBundles) {
|
|
4018
|
+
const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
|
|
4019
|
+
if (bundle?.subAgents) {
|
|
4020
|
+
for (const agent of bundle.subAgents) {
|
|
4021
|
+
agentMap.set(agent.name, agent);
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
3283
4026
|
if (this.options.subAgents) {
|
|
3284
4027
|
for (const agent of this.options.subAgents) {
|
|
3285
4028
|
agentMap.set(agent.name, agent);
|
|
@@ -3287,6 +4030,35 @@ ${extra}`
|
|
|
3287
4030
|
}
|
|
3288
4031
|
return [...agentMap.values()];
|
|
3289
4032
|
}
|
|
4033
|
+
resolveProcedures() {
|
|
4034
|
+
const procMap = /* @__PURE__ */ new Map();
|
|
4035
|
+
if (this.options.autoDetectBundles !== false) {
|
|
4036
|
+
for (const bundle of BUILT_IN_BUNDLES) {
|
|
4037
|
+
if (this.options.excludeBundles?.includes(bundle.name)) continue;
|
|
4038
|
+
if (bundle.appliesWhen(this.project) && bundle.procedures) {
|
|
4039
|
+
for (const proc of bundle.procedures) {
|
|
4040
|
+
procMap.set(proc.name, proc);
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
if (this.options.includeBundles) {
|
|
4046
|
+
for (const bundleName of this.options.includeBundles) {
|
|
4047
|
+
const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);
|
|
4048
|
+
if (bundle?.procedures) {
|
|
4049
|
+
for (const proc of bundle.procedures) {
|
|
4050
|
+
procMap.set(proc.name, proc);
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
}
|
|
4055
|
+
if (this.options.procedures) {
|
|
4056
|
+
for (const proc of this.options.procedures) {
|
|
4057
|
+
procMap.set(proc.name, proc);
|
|
4058
|
+
}
|
|
4059
|
+
}
|
|
4060
|
+
return [...procMap.values()];
|
|
4061
|
+
}
|
|
3290
4062
|
/**
|
|
3291
4063
|
* Resolves template variables in rule content using project metadata.
|
|
3292
4064
|
* Emits synthesis warnings for rules with unresolved variables.
|
|
@@ -3339,6 +4111,23 @@ ${extra}`
|
|
|
3339
4111
|
return resolved !== agent.prompt ? { ...agent, prompt: resolved } : agent;
|
|
3340
4112
|
});
|
|
3341
4113
|
}
|
|
4114
|
+
/**
|
|
4115
|
+
* Resolves template variables in procedure content using project metadata.
|
|
4116
|
+
*/
|
|
4117
|
+
resolveProcedureTemplates(procedures, metadata) {
|
|
4118
|
+
return procedures.map((proc) => {
|
|
4119
|
+
const { resolved, unresolvedKeys } = resolveTemplateVariables(
|
|
4120
|
+
proc.content,
|
|
4121
|
+
metadata
|
|
4122
|
+
);
|
|
4123
|
+
if (unresolvedKeys.length > 0) {
|
|
4124
|
+
this.project.logger.warn(
|
|
4125
|
+
`AgentConfig: ProjectMetadata not found; procedure '${proc.name}' using default values`
|
|
4126
|
+
);
|
|
4127
|
+
}
|
|
4128
|
+
return resolved !== proc.content ? { ...proc, content: resolved } : proc;
|
|
4129
|
+
});
|
|
4130
|
+
}
|
|
3342
4131
|
/**
|
|
3343
4132
|
* Collects Claude permission entries from all active bundles.
|
|
3344
4133
|
*/
|
|
@@ -5018,6 +5807,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen17.Compone
|
|
|
5018
5807
|
githubWorkflowBundle,
|
|
5019
5808
|
jestBundle,
|
|
5020
5809
|
meetingAnalysisBundle,
|
|
5810
|
+
orchestratorBundle,
|
|
5021
5811
|
pnpmBundle,
|
|
5022
5812
|
projenBundle,
|
|
5023
5813
|
resolveModelAlias,
|