great-cto 2.80.1 → 2.81.0

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.
@@ -2,7 +2,7 @@
2
2
  "name": "great_cto",
3
3
  "id": "great_cto",
4
4
  "description": "Engineering process for solo founders and teams up to 50 engineers. Agents do architecture, code review, QA, and security. You make two decisions per feature.",
5
- "version": "2.80.1",
5
+ "version": "2.81.0",
6
6
  "author": {
7
7
  "name": "Great CTO",
8
8
  "url": "https://github.com/avelikiy/great_cto"
@@ -62,7 +62,7 @@
62
62
  },
63
63
  {
64
64
  "type": "command",
65
- "command": "export PATH=\"/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\"; PLUGIN_DIR=$(ls -d ~/.claude/plugins/cache/local/great_cto/*/ 2>/dev/null | sort -V | tail -1 | sed 's|/$||'); if [ -z \"$PLUGIN_DIR\" ]; then echo 'GREAT_CTO: plugin dir not found \u2014 run /update'; else mkdir -p ~/.claude/commands ~/.claude/agents ~/.great_cto .great_cto; for STALE in triage gates dora investigate threat-model sbom security-incident update status capture revisit board-report; do STALE_F=~/.claude/commands/${STALE}.md; [ -f \"$STALE_F\" ] && grep -q 'great_cto-managed' \"$STALE_F\" 2>/dev/null && rm -f \"$STALE_F\" 2>/dev/null; done; for CMD in start audit inbox board digest review recall ownership oncall rfc release doctor burn cost sec poc promote crystallize migrate resume save learn agent-review agent-retire help voice-compliance aedt-bias-audit api-contract-review discover gen-evals prd prompt-evolve skillify spec ccr exception trace coding-audit gov-metrics; do if cp \"${PLUGIN_DIR}/commands/${CMD}.md\" ~/.claude/commands/${CMD}.md 2>/dev/null; then grep -q 'great_cto-managed' ~/.claude/commands/${CMD}.md 2>/dev/null || echo '<!-- great_cto-managed -->' >> ~/.claude/commands/${CMD}.md; fi; done; for STALE_AGENT in tech-lead; do STALE_AF=~/.claude/agents/great_cto-${STALE_AGENT}.md; [ -f \"$STALE_AF\" ] && grep -q 'great_cto-managed' \"$STALE_AF\" 2>/dev/null && rm -f \"$STALE_AF\" 2>/dev/null; done; for AGENT in product-owner architect senior-dev code-reviewer qa-engineer e2e-test-engineer security-officer devops l3-support project-auditor ai-prompt-architect ai-eval-engineer ai-security-reviewer web-store-reviewer pci-reviewer oracle-reviewer firmware-reviewer regulated-reviewer performance-engineer db-migration-reviewer pm mobile-store-reviewer library-reviewer infra-reviewer cli-reviewer game-reviewer data-platform-reviewer devtools-reviewer enterprise-saas-reviewer mlops-reviewer streaming-reviewer marketplace-reviewer cms-reviewer continuous-learner edtech-reviewer gov-reviewer insurance-reviewer voice-ai-reviewer hr-ai-reviewer api-platform-reviewer gdpr-reviewer us-privacy-reviewer dpdpa-reviewer adtech-privacy-reviewer cmmc-reviewer us-ai-reviewer legal-reviewer coordinator; do if cp \"${PLUGIN_DIR}/agents/${AGENT}.md\" ~/.claude/agents/great_cto-${AGENT}.md 2>/dev/null; then grep -q 'great_cto-managed' ~/.claude/agents/great_cto-${AGENT}.md 2>/dev/null || echo '<!-- great_cto-managed -->' >> ~/.claude/agents/great_cto-${AGENT}.md; fi; done; cp \"${PLUGIN_DIR}/skills/great_cto/ARCHETYPES.md\" .great_cto/ARCHETYPES.md 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/SKILL.md\" .great_cto/SKILL.md 2>/dev/null || true; { printf \"export PATH=/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\\nexport ARCHETYPES_MD=.great_cto/ARCHETYPES.md\\n\"; } > .great_cto/env.sh; fi; if [ ! -d ~/.great_cto/catalog ]; then git clone --depth=1 https://github.com/davila7/claude-code-templates.git ~/.great_cto/catalog 2>/dev/null & fi; if [ ! -d ~/.great_cto/anthropic-skills ]; then git clone --depth=1 https://github.com/anthropics/skills.git ~/.great_cto/anthropic-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/anthropic-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/anthropic-skills/.git 2>/dev/null || echo 0))) -gt 604800 ]; then (cd ~/.great_cto/anthropic-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -d ~/.great_cto/personal-skills ]; then git clone --depth=1 https://github.com/avelikiy/ai-agent-skills.git ~/.great_cto/personal-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/personal-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/personal-skills/.git 2>/dev/null || echo 0))) -gt 86400 ]; then (cd ~/.great_cto/personal-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -f ~/.great_cto/skills-registry.json ] || [ $(($(date +%s) - $(stat -f %m ~/.great_cto/skills-registry.json 2>/dev/null || stat -c %Y ~/.great_cto/skills-registry.json 2>/dev/null || echo 0))) -gt 86400 ]; then [ -x \"${PLUGIN_DIR}/scripts/skill-discover.sh\" ] && bash \"${PLUGIN_DIR}/scripts/skill-discover.sh\" >/dev/null 2>&1 & fi; [ -x \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" ] && bash \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" 2>/dev/null || true; bash \"${PLUGIN_DIR}/scripts/apply-model-override.sh\" 2>/dev/null || true; bd prime 2>/dev/null || true; echo '=== PREFERENCES ==='; cat ~/.great_cto/preferences.md 2>/dev/null || true; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null || echo 'GREAT_CTO: No PROJECT.md \u2014 run /start'; PHASE=$(grep '^phase:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' || echo implementation); echo '=== PHASE ==='; echo \"$PHASE\"; { [ \"$PHASE\" != review ] && [ \"$PHASE\" != release ]; } && { echo '=== BRAIN ==='; head -30 .great_cto/brain.md 2>/dev/null; } || true; [ \"$PHASE\" = implementation ] && { echo '=== CODEBASE ==='; head -20 .great_cto/CODEBASE.md 2>/dev/null; } || true; echo '=== LOCAL ==='; cat .great_cto/local.md 2>/dev/null || true; [ \"$PHASE\" != planning ] && { echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null || echo 'No handoff state \u2014 fresh session'; } || true; [ \"$PHASE\" = review ] && { echo '=== LATEST QA ==='; ls docs/qa-reports/QA-*.md 2>/dev/null | sort -V | tail -1 | xargs head -20 2>/dev/null; echo '=== LATEST CSO ==='; ls docs/security/CSO-*.md 2>/dev/null | sort -V | tail -1 | xargs head -20 2>/dev/null; } || true; [ \"$PHASE\" = release ] && { echo '=== PERF BASELINE ==='; tail -10 .great_cto/perf-baseline.log 2>/dev/null; } || true; echo '=== STATUS ==='; OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | wc -l | tr -d ' '); OPEN_TASKS=$(bd list --status open 2>/dev/null | wc -l | tr -d ' '); BRANCH=$(git branch --show-current 2>/dev/null || echo '?'); LAST_AGENT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null | awk '{print $2}' || echo 'none'); printf 'branch=%s | gates=%s | tasks=%s | last_agent=%s\\n' \"$BRANCH\" \"${OPEN_GATES:-0}\" \"${OPEN_TASKS:-0}\" \"${LAST_AGENT:-none}\"; [ \"${OPEN_GATES:-0}\" -gt 0 ] && echo '\u2192 run /inbox to see pending decisions' || true; P0_OPEN=$(bd list --status open 2>/dev/null | grep -c 'P0'); P0_OPEN=${P0_OPEN:-0}; if [ \"$P0_OPEN\" -gt 0 ]; then echo ''; printf '\\033[41;97m \ud83d\udea8 P0 OPEN: %s \u2014 run /inbox NOW \\033[0m\\n' \"$P0_OPEN\"; bd list --status open 2>/dev/null | grep 'P0' | head -3 | sed 's/^/ /'; fi; NOW_EPOCH=$(date +%s); LAST_AUDIT_FILE=$(find docs/audit -maxdepth 1 -name 'AUDIT-*.md' 2>/dev/null | sort | tail -1); if [ -n \"$LAST_AUDIT_FILE\" ]; then AUD_M=$(stat -f %m \"$LAST_AUDIT_FILE\" 2>/dev/null || stat -c %Y \"$LAST_AUDIT_FILE\" 2>/dev/null || echo $NOW_EPOCH); AUD_AGE=$(( (NOW_EPOCH - AUD_M) / 86400 )); [ \"$AUD_AGE\" -gt 30 ] && echo \"\u26a0 audit $AUD_AGE days old \u2014 run /audit\"; else echo '\u26a0 no audit artefact \u2014 run /audit or /doctor'; fi; if [ -f .great_cto/digest-latest.md ]; then DIG_M=$(stat -f %m .great_cto/digest-latest.md 2>/dev/null || stat -c %Y .great_cto/digest-latest.md 2>/dev/null || echo $NOW_EPOCH); DIG_AGE=$(( (NOW_EPOCH - DIG_M) / 86400 )); [ \"$DIG_AGE\" -gt 8 ] && echo \"\u26a0 digest $DIG_AGE days old \u2014 run /digest 7\"; fi; [ \"$PHASE\" != implementation ] && cat .great_cto/digest-latest.md 2>/dev/null | head -5 || true; [ -f \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" ] && node \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" 2>/dev/null; node \"${PLUGIN_DIR}/scripts/hooks/quota-check.mjs\" 2>/dev/null || true; echo '=== PATTERNS ==='; GP_DIR=\"$HOME/.great_cto/global-patterns\"; ARCH=$(grep '^primary:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' | head -1); if [ -d \"$GP_DIR\" ] && ls \"$GP_DIR\"/GP-*.md >/dev/null 2>&1; then ACTIVE_COUNT=$(grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | wc -l | tr -d ' '); echo \"Active patterns: ${ACTIVE_COUNT:-0}\"; if [ -n \"$ARCH\" ] && [ \"${ACTIVE_COUNT:-0}\" -gt 0 ]; then grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | xargs grep -lE \"applies_to:.*$ARCH\" 2>/dev/null | sort -V | tail -5 | while read f; do SLUG=$(basename \"$f\" .md); SYMPT=$(grep -m1 '^symptom:' \"$f\" 2>/dev/null | sed 's/symptom: //'); DETECT=$(grep -A 2 '^detection_order:' \"$f\" 2>/dev/null | grep '^ - ' | head -1 | sed 's/^ - //'); HITS=$(grep -m1 '^hits:' \"$f\" 2>/dev/null | awk '{print $2}'); printf ' %s (hits=%s): %s\\n \\u2192 Check first: %s\\n' \"$SLUG\" \"${HITS:-0}\" \"$SYMPT\" \"$DETECT\"; done || echo \" no patterns match archetype=$ARCH yet \u2014 /crystallize builds the library\"; fi; else echo 'no global patterns yet \u2014 run /crystallize after first incident'; fi; [ -x \"${PLUGIN_DIR}/scripts/check-update.sh\" ] && bash \"${PLUGIN_DIR}/scripts/check-update.sh\" \"${PLUGIN_DIR}/.claude-plugin/plugin.json\" 2>/dev/null || true ; # great_cto-cache-cleanup v2.5.8: keep only 3 most recent cached versions to prevent disk bloat. ls -d \"$HOME\"/.claude/plugins/cache/local/great_cto/*/ 2>/dev/null | sort -V | awk -v k=3 '{a[NR]=$0} END {for (i=1; i<=NR-k; i++) print a[i]}' | xargs -I{} rm -rf {} 2>/dev/null || true",
65
+ "command": "export PATH=\"/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\"; PLUGIN_DIR=$(ls -d ~/.claude/plugins/cache/local/great_cto/*/ 2>/dev/null | sort -V | tail -1 | sed 's|/$||'); if [ -z \"$PLUGIN_DIR\" ]; then echo 'GREAT_CTO: plugin dir not found \u2014 run /update'; else mkdir -p ~/.claude/commands ~/.claude/agents ~/.great_cto .great_cto; for STALE in triage gates dora investigate threat-model sbom security-incident update status capture revisit board-report; do STALE_F=~/.claude/commands/${STALE}.md; [ -f \"$STALE_F\" ] && grep -q 'great_cto-managed' \"$STALE_F\" 2>/dev/null && rm -f \"$STALE_F\" 2>/dev/null; done; for CMD in start audit inbox board digest review recall ownership oncall rfc release doctor burn cost sec poc promote crystallize migrate resume save learn agent-review agent-retire help voice-compliance aedt-bias-audit api-contract-review discover gen-evals prd prompt-evolve skillify spec ccr exception trace coding-audit gov-metrics upl-check; do if cp \"${PLUGIN_DIR}/commands/${CMD}.md\" ~/.claude/commands/${CMD}.md 2>/dev/null; then grep -q 'great_cto-managed' ~/.claude/commands/${CMD}.md 2>/dev/null || echo '<!-- great_cto-managed -->' >> ~/.claude/commands/${CMD}.md; fi; done; for STALE_AGENT in tech-lead; do STALE_AF=~/.claude/agents/great_cto-${STALE_AGENT}.md; [ -f \"$STALE_AF\" ] && grep -q 'great_cto-managed' \"$STALE_AF\" 2>/dev/null && rm -f \"$STALE_AF\" 2>/dev/null; done; for AGENT in product-owner architect senior-dev code-reviewer qa-engineer e2e-test-engineer security-officer devops l3-support project-auditor ai-prompt-architect ai-eval-engineer ai-security-reviewer web-store-reviewer pci-reviewer oracle-reviewer firmware-reviewer regulated-reviewer performance-engineer db-migration-reviewer pm mobile-store-reviewer library-reviewer infra-reviewer cli-reviewer game-reviewer data-platform-reviewer devtools-reviewer enterprise-saas-reviewer mlops-reviewer streaming-reviewer marketplace-reviewer cms-reviewer continuous-learner edtech-reviewer gov-reviewer insurance-reviewer voice-ai-reviewer hr-ai-reviewer api-platform-reviewer gdpr-reviewer us-privacy-reviewer dpdpa-reviewer adtech-privacy-reviewer cmmc-reviewer us-ai-reviewer legal-reviewer coordinator; do if cp \"${PLUGIN_DIR}/agents/${AGENT}.md\" ~/.claude/agents/great_cto-${AGENT}.md 2>/dev/null; then grep -q 'great_cto-managed' ~/.claude/agents/great_cto-${AGENT}.md 2>/dev/null || echo '<!-- great_cto-managed -->' >> ~/.claude/agents/great_cto-${AGENT}.md; fi; done; cp \"${PLUGIN_DIR}/skills/great_cto/ARCHETYPES.md\" .great_cto/ARCHETYPES.md 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/SKILL.md\" .great_cto/SKILL.md 2>/dev/null || true; { printf \"export PATH=/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\\nexport ARCHETYPES_MD=.great_cto/ARCHETYPES.md\\n\"; } > .great_cto/env.sh; fi; if [ ! -d ~/.great_cto/catalog ]; then git clone --depth=1 https://github.com/davila7/claude-code-templates.git ~/.great_cto/catalog 2>/dev/null & fi; if [ ! -d ~/.great_cto/anthropic-skills ]; then git clone --depth=1 https://github.com/anthropics/skills.git ~/.great_cto/anthropic-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/anthropic-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/anthropic-skills/.git 2>/dev/null || echo 0))) -gt 604800 ]; then (cd ~/.great_cto/anthropic-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -d ~/.great_cto/personal-skills ]; then git clone --depth=1 https://github.com/avelikiy/ai-agent-skills.git ~/.great_cto/personal-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/personal-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/personal-skills/.git 2>/dev/null || echo 0))) -gt 86400 ]; then (cd ~/.great_cto/personal-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -f ~/.great_cto/skills-registry.json ] || [ $(($(date +%s) - $(stat -f %m ~/.great_cto/skills-registry.json 2>/dev/null || stat -c %Y ~/.great_cto/skills-registry.json 2>/dev/null || echo 0))) -gt 86400 ]; then [ -x \"${PLUGIN_DIR}/scripts/skill-discover.sh\" ] && bash \"${PLUGIN_DIR}/scripts/skill-discover.sh\" >/dev/null 2>&1 & fi; [ -x \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" ] && bash \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" 2>/dev/null || true; bash \"${PLUGIN_DIR}/scripts/apply-model-override.sh\" 2>/dev/null || true; bd prime 2>/dev/null || true; echo '=== PREFERENCES ==='; cat ~/.great_cto/preferences.md 2>/dev/null || true; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null || echo 'GREAT_CTO: No PROJECT.md \u2014 run /start'; PHASE=$(grep '^phase:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' || echo implementation); echo '=== PHASE ==='; echo \"$PHASE\"; { [ \"$PHASE\" != review ] && [ \"$PHASE\" != release ]; } && { echo '=== BRAIN ==='; head -30 .great_cto/brain.md 2>/dev/null; } || true; [ \"$PHASE\" = implementation ] && { echo '=== CODEBASE ==='; head -20 .great_cto/CODEBASE.md 2>/dev/null; } || true; echo '=== LOCAL ==='; cat .great_cto/local.md 2>/dev/null || true; [ \"$PHASE\" != planning ] && { echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null || echo 'No handoff state \u2014 fresh session'; } || true; [ \"$PHASE\" = review ] && { echo '=== LATEST QA ==='; ls docs/qa-reports/QA-*.md 2>/dev/null | sort -V | tail -1 | xargs head -20 2>/dev/null; echo '=== LATEST CSO ==='; ls docs/security/CSO-*.md 2>/dev/null | sort -V | tail -1 | xargs head -20 2>/dev/null; } || true; [ \"$PHASE\" = release ] && { echo '=== PERF BASELINE ==='; tail -10 .great_cto/perf-baseline.log 2>/dev/null; } || true; echo '=== STATUS ==='; OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | wc -l | tr -d ' '); OPEN_TASKS=$(bd list --status open 2>/dev/null | wc -l | tr -d ' '); BRANCH=$(git branch --show-current 2>/dev/null || echo '?'); LAST_AGENT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null | awk '{print $2}' || echo 'none'); printf 'branch=%s | gates=%s | tasks=%s | last_agent=%s\\n' \"$BRANCH\" \"${OPEN_GATES:-0}\" \"${OPEN_TASKS:-0}\" \"${LAST_AGENT:-none}\"; [ \"${OPEN_GATES:-0}\" -gt 0 ] && echo '\u2192 run /inbox to see pending decisions' || true; P0_OPEN=$(bd list --status open 2>/dev/null | grep -c 'P0'); P0_OPEN=${P0_OPEN:-0}; if [ \"$P0_OPEN\" -gt 0 ]; then echo ''; printf '\\033[41;97m \ud83d\udea8 P0 OPEN: %s \u2014 run /inbox NOW \\033[0m\\n' \"$P0_OPEN\"; bd list --status open 2>/dev/null | grep 'P0' | head -3 | sed 's/^/ /'; fi; NOW_EPOCH=$(date +%s); LAST_AUDIT_FILE=$(find docs/audit -maxdepth 1 -name 'AUDIT-*.md' 2>/dev/null | sort | tail -1); if [ -n \"$LAST_AUDIT_FILE\" ]; then AUD_M=$(stat -f %m \"$LAST_AUDIT_FILE\" 2>/dev/null || stat -c %Y \"$LAST_AUDIT_FILE\" 2>/dev/null || echo $NOW_EPOCH); AUD_AGE=$(( (NOW_EPOCH - AUD_M) / 86400 )); [ \"$AUD_AGE\" -gt 30 ] && echo \"\u26a0 audit $AUD_AGE days old \u2014 run /audit\"; else echo '\u26a0 no audit artefact \u2014 run /audit or /doctor'; fi; if [ -f .great_cto/digest-latest.md ]; then DIG_M=$(stat -f %m .great_cto/digest-latest.md 2>/dev/null || stat -c %Y .great_cto/digest-latest.md 2>/dev/null || echo $NOW_EPOCH); DIG_AGE=$(( (NOW_EPOCH - DIG_M) / 86400 )); [ \"$DIG_AGE\" -gt 8 ] && echo \"\u26a0 digest $DIG_AGE days old \u2014 run /digest 7\"; fi; [ \"$PHASE\" != implementation ] && cat .great_cto/digest-latest.md 2>/dev/null | head -5 || true; [ -f \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" ] && node \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" 2>/dev/null; node \"${PLUGIN_DIR}/scripts/hooks/quota-check.mjs\" 2>/dev/null || true; echo '=== PATTERNS ==='; GP_DIR=\"$HOME/.great_cto/global-patterns\"; ARCH=$(grep '^primary:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' | head -1); if [ -d \"$GP_DIR\" ] && ls \"$GP_DIR\"/GP-*.md >/dev/null 2>&1; then ACTIVE_COUNT=$(grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | wc -l | tr -d ' '); echo \"Active patterns: ${ACTIVE_COUNT:-0}\"; if [ -n \"$ARCH\" ] && [ \"${ACTIVE_COUNT:-0}\" -gt 0 ]; then grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | xargs grep -lE \"applies_to:.*$ARCH\" 2>/dev/null | sort -V | tail -5 | while read f; do SLUG=$(basename \"$f\" .md); SYMPT=$(grep -m1 '^symptom:' \"$f\" 2>/dev/null | sed 's/symptom: //'); DETECT=$(grep -A 2 '^detection_order:' \"$f\" 2>/dev/null | grep '^ - ' | head -1 | sed 's/^ - //'); HITS=$(grep -m1 '^hits:' \"$f\" 2>/dev/null | awk '{print $2}'); printf ' %s (hits=%s): %s\\n \\u2192 Check first: %s\\n' \"$SLUG\" \"${HITS:-0}\" \"$SYMPT\" \"$DETECT\"; done || echo \" no patterns match archetype=$ARCH yet \u2014 /crystallize builds the library\"; fi; else echo 'no global patterns yet \u2014 run /crystallize after first incident'; fi; [ -x \"${PLUGIN_DIR}/scripts/check-update.sh\" ] && bash \"${PLUGIN_DIR}/scripts/check-update.sh\" \"${PLUGIN_DIR}/.claude-plugin/plugin.json\" 2>/dev/null || true ; # great_cto-cache-cleanup v2.5.8: keep only 3 most recent cached versions to prevent disk bloat. ls -d \"$HOME\"/.claude/plugins/cache/local/great_cto/*/ 2>/dev/null | sort -V | awk -v k=3 '{a[NR]=$0} END {for (i=1; i<=NR-k; i++) print a[i]}' | xargs -I{} rm -rf {} 2>/dev/null || true",
66
66
  "timeout": 30,
67
67
  "statusMessage": "Loading Great CTO context..."
68
68
  },
@@ -1037,12 +1037,63 @@ const RULES = [
1037
1037
  return `insurance detected (${bits.join(", ") || "insurance domain signals"}) — NAIC/Solvency II/actuarial-audit gates required`;
1038
1038
  },
1039
1039
  },
1040
+ // ── legal (legal-smb — UPL / IOLTA / privilege / conflicts) ──
1041
+ // Distinct from enterprise-saas/regulated: the dominant obligations are
1042
+ // ethical/fiduciary (state bar rules), not security-framework compliance.
1043
+ {
1044
+ archetype: "legal",
1045
+ score: (d) => {
1046
+ let s = 0;
1047
+ const legalLibs = ["clio-sdk", "mycase-sdk", "pacer-api", "cm-ecf",
1048
+ "clio", "mycase"];
1049
+ legalLibs.forEach((l) => { if (d.stack.includes(l))
1050
+ s += 6; });
1051
+ const kws = d.readmeKeywords;
1052
+ const legalKeywords = ["matter", "docket", "litigation", "retainer",
1053
+ "iolta", "clio", "mycase", "pacer", "ecf",
1054
+ "cm/ecf", "conflict-check", "engagement-letter",
1055
+ "paralegal", "law-firm", "attorney"];
1056
+ const matchedKws = legalKeywords.filter((k) => kws.includes(k));
1057
+ if (matchedKws.length >= 3)
1058
+ s += 6;
1059
+ else if (matchedKws.length === 2)
1060
+ s += 3;
1061
+ else if (matchedKws.length === 1)
1062
+ s += 1;
1063
+ // Very strong signals — IOLTA / UPL explicit
1064
+ if (kws.includes("iolta"))
1065
+ s += 5;
1066
+ if (kws.includes("law-firm") || kws.includes("attorney"))
1067
+ s += 3;
1068
+ if (kws.includes("upl") || kws.includes("unauthorized practice of law"))
1069
+ s += 4;
1070
+ return s;
1071
+ },
1072
+ reason: (d) => {
1073
+ const kws = d.readmeKeywords;
1074
+ const bits = [];
1075
+ const legalLibs = ["clio-sdk", "mycase-sdk", "pacer-api", "cm-ecf"];
1076
+ legalLibs.forEach((l) => { if (d.stack.includes(l))
1077
+ bits.push(l); });
1078
+ if (kws.includes("iolta"))
1079
+ bits.push("IOLTA mention");
1080
+ if (kws.includes("matter"))
1081
+ bits.push("matter keyword");
1082
+ if (kws.includes("docket"))
1083
+ bits.push("docket keyword");
1084
+ if (kws.includes("law-firm"))
1085
+ bits.push("law-firm keyword");
1086
+ if (kws.includes("attorney"))
1087
+ bits.push("attorney keyword");
1088
+ return `legal detected (${bits.join(", ") || "legal domain signals"}) — UPL/IOLTA/privilege/conflict-check gates required`;
1089
+ },
1090
+ },
1040
1091
  ];
1041
1092
  // Tie-break priority — when two rules score equally, prefer the one
1042
1093
  // higher in this list (more specific / domain-bound first).
1043
1094
  const TIE_BREAK_PRIORITY = [
1044
1095
  "browser-extension", "iot-embedded", "web3", "game",
1045
- "agent-product", "fintech", "insurance", "healthcare", "edtech", "defense-govcon", "gov-public", "marketplace",
1096
+ "agent-product", "fintech", "insurance", "legal", "healthcare", "edtech", "defense-govcon", "gov-public", "marketplace",
1046
1097
  "mlops", "streaming",
1047
1098
  "commerce", "enterprise-saas", "ai-system", "devtools",
1048
1099
  "data-platform", "cms", "infra", "mobile-app",
@@ -1250,6 +1301,15 @@ export function suggestCompliance(d, archetype) {
1250
1301
  c.add("naic-ai-model-bulletin");
1251
1302
  c.add("colorado-sb-21-169"); // US insurance-AI rules
1252
1303
  }
1304
+ if (archetype === "legal") {
1305
+ c.add("upl");
1306
+ c.add("iolta");
1307
+ c.add("aba-model-rule-1.6");
1308
+ c.add("aba-model-rules-1.7-1.9");
1309
+ c.add("frcp-5.2");
1310
+ c.add("gdpr");
1311
+ c.add("ccpa");
1312
+ }
1253
1313
  if (archetype === "defense-govcon") {
1254
1314
  c.add("cmmc-2.0");
1255
1315
  c.add("nist-800-171");
@@ -1317,6 +1377,7 @@ export const REVIEWERS_BY_ARCHETYPE = {
1317
1377
  "edtech": ["edtech-reviewer"],
1318
1378
  "gov-public": ["gov-reviewer", "security-officer"],
1319
1379
  "insurance": ["insurance-reviewer", "regulated-reviewer"],
1380
+ "legal": ["legal-reviewer", "security-officer"],
1320
1381
  "defense-govcon": ["cmmc-reviewer", "gov-reviewer", "security-officer"],
1321
1382
  // Product Builder archetypes (A1–A6) — lean reviewer sets; payments → pci.
1322
1383
  "vertical-saas": ["security-officer"],
@@ -1360,6 +1421,7 @@ export const GATES_BY_ARCHETYPE = {
1360
1421
  "edtech": ["plan", "qa", "edtech-review", "security", "ship", "compliance"],
1361
1422
  "gov-public": ["plan", "qa", "gov-review", "security", "ship", "compliance"],
1362
1423
  "insurance": ["plan", "qa", "insurance-review", "security", "ship", "compliance"],
1424
+ "legal": ["plan", "qa", "upl-review", "security", "ship", "compliance"],
1363
1425
  "defense-govcon": ["plan", "qa", "cmmc-assessment", "security", "ship", "compliance"],
1364
1426
  // Product Builder archetypes (A1–A6) — non-regulated baseline; the single CTO gate
1365
1427
  // emerges at change_tier T1 (effectiveGates → [plan]).
@@ -1037,12 +1037,63 @@ const RULES = [
1037
1037
  return `insurance detected (${bits.join(", ") || "insurance domain signals"}) — NAIC/Solvency II/actuarial-audit gates required`;
1038
1038
  },
1039
1039
  },
1040
+ // ── legal (legal-smb — UPL / IOLTA / privilege / conflicts) ──
1041
+ // Distinct from enterprise-saas/regulated: the dominant obligations are
1042
+ // ethical/fiduciary (state bar rules), not security-framework compliance.
1043
+ {
1044
+ archetype: "legal",
1045
+ score: (d) => {
1046
+ let s = 0;
1047
+ const legalLibs = ["clio-sdk", "mycase-sdk", "pacer-api", "cm-ecf",
1048
+ "clio", "mycase"];
1049
+ legalLibs.forEach((l) => { if (d.stack.includes(l))
1050
+ s += 6; });
1051
+ const kws = d.readmeKeywords;
1052
+ const legalKeywords = ["matter", "docket", "litigation", "retainer",
1053
+ "iolta", "clio", "mycase", "pacer", "ecf",
1054
+ "cm/ecf", "conflict-check", "engagement-letter",
1055
+ "paralegal", "law-firm", "attorney"];
1056
+ const matchedKws = legalKeywords.filter((k) => kws.includes(k));
1057
+ if (matchedKws.length >= 3)
1058
+ s += 6;
1059
+ else if (matchedKws.length === 2)
1060
+ s += 3;
1061
+ else if (matchedKws.length === 1)
1062
+ s += 1;
1063
+ // Very strong signals — IOLTA / UPL explicit
1064
+ if (kws.includes("iolta"))
1065
+ s += 5;
1066
+ if (kws.includes("law-firm") || kws.includes("attorney"))
1067
+ s += 3;
1068
+ if (kws.includes("upl") || kws.includes("unauthorized practice of law"))
1069
+ s += 4;
1070
+ return s;
1071
+ },
1072
+ reason: (d) => {
1073
+ const kws = d.readmeKeywords;
1074
+ const bits = [];
1075
+ const legalLibs = ["clio-sdk", "mycase-sdk", "pacer-api", "cm-ecf"];
1076
+ legalLibs.forEach((l) => { if (d.stack.includes(l))
1077
+ bits.push(l); });
1078
+ if (kws.includes("iolta"))
1079
+ bits.push("IOLTA mention");
1080
+ if (kws.includes("matter"))
1081
+ bits.push("matter keyword");
1082
+ if (kws.includes("docket"))
1083
+ bits.push("docket keyword");
1084
+ if (kws.includes("law-firm"))
1085
+ bits.push("law-firm keyword");
1086
+ if (kws.includes("attorney"))
1087
+ bits.push("attorney keyword");
1088
+ return `legal detected (${bits.join(", ") || "legal domain signals"}) — UPL/IOLTA/privilege/conflict-check gates required`;
1089
+ },
1090
+ },
1040
1091
  ];
1041
1092
  // Tie-break priority — when two rules score equally, prefer the one
1042
1093
  // higher in this list (more specific / domain-bound first).
1043
1094
  const TIE_BREAK_PRIORITY = [
1044
1095
  "browser-extension", "iot-embedded", "web3", "game",
1045
- "agent-product", "fintech", "insurance", "healthcare", "edtech", "defense-govcon", "gov-public", "marketplace",
1096
+ "agent-product", "fintech", "insurance", "legal", "healthcare", "edtech", "defense-govcon", "gov-public", "marketplace",
1046
1097
  "mlops", "streaming",
1047
1098
  "commerce", "enterprise-saas", "ai-system", "devtools",
1048
1099
  "data-platform", "cms", "infra", "mobile-app",
@@ -1250,6 +1301,15 @@ export function suggestCompliance(d, archetype) {
1250
1301
  c.add("naic-ai-model-bulletin");
1251
1302
  c.add("colorado-sb-21-169"); // US insurance-AI rules
1252
1303
  }
1304
+ if (archetype === "legal") {
1305
+ c.add("upl");
1306
+ c.add("iolta");
1307
+ c.add("aba-model-rule-1.6");
1308
+ c.add("aba-model-rules-1.7-1.9");
1309
+ c.add("frcp-5.2");
1310
+ c.add("gdpr");
1311
+ c.add("ccpa");
1312
+ }
1253
1313
  if (archetype === "defense-govcon") {
1254
1314
  c.add("cmmc-2.0");
1255
1315
  c.add("nist-800-171");
@@ -1317,6 +1377,7 @@ export const REVIEWERS_BY_ARCHETYPE = {
1317
1377
  "edtech": ["edtech-reviewer"],
1318
1378
  "gov-public": ["gov-reviewer", "security-officer"],
1319
1379
  "insurance": ["insurance-reviewer", "regulated-reviewer"],
1380
+ "legal": ["legal-reviewer", "security-officer"],
1320
1381
  "defense-govcon": ["cmmc-reviewer", "gov-reviewer", "security-officer"],
1321
1382
  // Product Builder archetypes (A1–A6) — lean reviewer sets; payments → pci.
1322
1383
  "vertical-saas": ["security-officer"],
@@ -1360,6 +1421,7 @@ export const GATES_BY_ARCHETYPE = {
1360
1421
  "edtech": ["plan", "qa", "edtech-review", "security", "ship", "compliance"],
1361
1422
  "gov-public": ["plan", "qa", "gov-review", "security", "ship", "compliance"],
1362
1423
  "insurance": ["plan", "qa", "insurance-review", "security", "ship", "compliance"],
1424
+ "legal": ["plan", "qa", "upl-review", "security", "ship", "compliance"],
1363
1425
  "defense-govcon": ["plan", "qa", "cmmc-assessment", "security", "ship", "compliance"],
1364
1426
  // Product Builder archetypes (A1–A6) — non-regulated baseline; the single CTO gate
1365
1427
  // emerges at change_tier T1 (effectiveGates → [plan]).
package/dist/flow.js CHANGED
@@ -30,6 +30,7 @@ const ARCHETYPE_TITLE = {
30
30
  "edtech": "EdTech",
31
31
  "gov-public": "Government",
32
32
  "insurance": "Insurance",
33
+ "legal": "Legal / Law firm",
33
34
  "regulated": "Regulated system",
34
35
  "vertical-saas": "Vertical SaaS",
35
36
  "booking": "Booking / scheduling",
@@ -53,6 +54,7 @@ const GATE_LABEL = {
53
54
  "edtech-review": "gate:edtech-review",
54
55
  "gov-review": "gate:gov-review",
55
56
  "insurance-review": "gate:insurance-review",
57
+ "upl-review": "gate:upl-review",
56
58
  "cmmc-assessment": "gate:cmmc-assessment",
57
59
  };
58
60
  // Cost (low, high) per feature cycle by archetype tier
@@ -67,6 +69,7 @@ const ARCHETYPE_COST = {
67
69
  "edtech": [8, 18],
68
70
  "gov-public": [8, 18],
69
71
  "insurance": [8, 18],
72
+ "legal": [8, 18],
70
73
  "web3": [8, 18],
71
74
  "commerce": [3, 8],
72
75
  "mobile-app": [3, 8],
@@ -100,7 +103,7 @@ const ARCHETYPE_COST = {
100
103
  export const UI_BEARING_ARCHETYPES = new Set([
101
104
  "web-service", "mobile-app", "commerce", "marketplace", "cms",
102
105
  "enterprise-saas", "edtech", "game", "browser-extension",
103
- "healthcare", "fintech", "insurance", "gov-public", "web3",
106
+ "healthcare", "fintech", "insurance", "legal", "gov-public", "web3",
104
107
  // Product Builder archetypes (A1–A6) — all ship a UI.
105
108
  "vertical-saas", "booking", "crm", "dashboard", "content-platform",
106
109
  "marketplace-lite",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.80.1",
3
+ "version": "2.81.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",