great-cto 2.14.0 → 2.16.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.
package/dist/bootstrap.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { dim, success, warn } from "./ui.js";
6
+ import { suggestJurisdictions } from "./jurisdictions.js";
6
7
  export function bootstrap(dir, detection, archetype, compliance, detectionMeta) {
7
8
  const greatCtoDir = join(dir, ".great_cto");
8
9
  const projectMd = join(greatCtoDir, "PROJECT.md");
@@ -14,6 +15,10 @@ export function bootstrap(dir, detection, archetype, compliance, detectionMeta)
14
15
  const title = inferProjectTitle(dir);
15
16
  const stackLine = detection.stack.length > 0 ? detection.stack.join(", ") : "to be defined";
16
17
  const complianceLine = compliance.length > 0 ? compliance.join(", ") : "none";
18
+ const jurisdictionMatches = suggestJurisdictions(detection);
19
+ const jurisdictionLine = jurisdictionMatches.length > 0
20
+ ? jurisdictionMatches.map((m) => m.jurisdiction).join(", ")
21
+ : "unknown";
17
22
  const teamSize = 1; // MVP default — user edits later
18
23
  const approvalLevel = "gates-only"; // default per README
19
24
  const content = `# ${title}
@@ -55,9 +60,12 @@ approval-level: ${approvalLevel}
55
60
  ## Compliance
56
61
 
57
62
  compliance: [${complianceLine}]
63
+ jurisdiction: [${jurisdictionLine}]
58
64
 
59
65
  > \`compliance:\` list drives which checklists security-officer runs.
60
- > See ARCHETYPES.md "Parameter Values" for supported keys.
66
+ > \`jurisdiction:\` is auto-detected from README geo/legal signals — edit if wrong.
67
+ > Supported codes: eu · us · us-ca · uk · in · br · au · sg
68
+ > See docs/jurisdiction-compliance.md for what each code activates.
61
69
 
62
70
  ## Leash
63
71
 
package/dist/detect.js CHANGED
@@ -1163,6 +1163,56 @@ function mineReadmeKeywords(dir) {
1163
1163
  if (text.includes(term))
1164
1164
  kws.add(term);
1165
1165
  }
1166
+ // Jurisdiction geo/legal terms — emitted verbatim so jurisdictions.ts
1167
+ // can exact-match them. Keep in sync with JURISDICTION_SIGNALS in jurisdictions.ts.
1168
+ const jurisdictionTerms = [
1169
+ // EU
1170
+ "gdpr", "dsgvo", "rgpd", "data protection officer", "dpo",
1171
+ "right to erasure", "right to be forgotten", "data subject request",
1172
+ "article 6", "article 9", "legitimate interest", "lawful basis",
1173
+ "privacy by design", "privacy notice", "cookie consent",
1174
+ "eu ai act", "eu users", "eu customers", "european union",
1175
+ "eu data residency", "eu-west", "eu-central",
1176
+ "nis2", "dora ict risk", "dora compliance",
1177
+ "german users", "french users", "dutch users", "austrian",
1178
+ "italian users", "spanish users", "polish users",
1179
+ // US
1180
+ "ftc", "ftc act", "us users", "us customers", "united states",
1181
+ "american users", "coppa", "hipaa", "us privacy law",
1182
+ "virginia cdpa", "texas tdpsa", "florida fdbr",
1183
+ "colorado cpa", "connecticut ctdpa", "us state privacy",
1184
+ // US-CA
1185
+ "ccpa", "cpra", "california consumer privacy",
1186
+ "california privacy rights", "cppa", "california residents",
1187
+ "california users", "do not sell", "opt-out of sale",
1188
+ "data subject rights california", "dsr california",
1189
+ // UK
1190
+ "uk gdpr", "information commissioner", "dpa 2018",
1191
+ "uk users", "uk customers", "united kingdom", "british users",
1192
+ "fca consumer duty", "uk ai regulation",
1193
+ // IN
1194
+ "dpdpa", "digital personal data protection", "india data",
1195
+ "india users", "indian users", "bharat", "meity",
1196
+ "rbi data localisation", "rbi circular", "npci", "sebi",
1197
+ "india data residency",
1198
+ // BR
1199
+ "lgpd", "lei 13709", "anpd", "brazil users", "brazil customers",
1200
+ "brazilian users", "brasil", "data encarregado", "dpo brazil",
1201
+ "lgpd compliance",
1202
+ // AU
1203
+ "privacy act 1988", "australian privacy principles", "app principles",
1204
+ "oaic", "australia users", "australian users",
1205
+ "consumer data right", "notifiable data breach", "ndb scheme",
1206
+ "australia data residency",
1207
+ // SG
1208
+ "pdpa", "pdpc", "singapore users", "singaporean users",
1209
+ "mas guidelines", "mas tpm", "singpass", "myinfo",
1210
+ "singapore data residency",
1211
+ ];
1212
+ for (const term of jurisdictionTerms) {
1213
+ if (text.includes(term))
1214
+ kws.add(term);
1215
+ }
1166
1216
  return Array.from(kws).sort();
1167
1217
  }
1168
1218
  function safeGlob(dir, pattern, kind = "file") {
@@ -0,0 +1,156 @@
1
+ // Jurisdiction detection — auto-detect applicable compliance frameworks
2
+ // from project geography signals (README keywords, infra region hints).
3
+ //
4
+ // Three-axis detection model:
5
+ // archetype → what you build (ai-system, healthcare, fintech…)
6
+ // pack → what you use (digital-health-pack, lending-pack…)
7
+ // jurisdiction → where you operate (eu, us-ca, in, br, uk, au, sg)
8
+ //
9
+ // Jurisdiction overlays add specialist reviewer agents and human gates
10
+ // ON TOP OF archetype + pack pipelines.
11
+ // ── Compliance map ────────────────────────────────────────────────────────
12
+ const JURISDICTION_REVIEWERS = {
13
+ "eu": ["gdpr-reviewer"],
14
+ "us": ["us-privacy-reviewer"],
15
+ "us-ca": ["us-privacy-reviewer"],
16
+ "uk": ["gdpr-reviewer"], // UK GDPR closely mirrors EU GDPR
17
+ "in": ["dpdpa-reviewer"],
18
+ "br": ["gdpr-reviewer"], // LGPD mirrors GDPR — same reviewer covers
19
+ "au": ["us-privacy-reviewer"], // Privacy Act 1988 — covered by privacy reviewer
20
+ "sg": ["us-privacy-reviewer"], // PDPA — covered by privacy reviewer
21
+ };
22
+ const JURISDICTION_GATES = {
23
+ "eu": ["gate:gdpr-dpia", "gate:eu-ai-act-classification"],
24
+ "us": ["gate:us-state-privacy-matrix"],
25
+ "us-ca": ["gate:ccpa-dsrp", "gate:us-state-privacy-matrix"],
26
+ "uk": ["gate:uk-gdpr-dpia"],
27
+ "in": ["gate:dpdpa-consent-framework"],
28
+ "br": ["gate:lgpd-dpia"],
29
+ "au": ["gate:au-privacy-act-assessment"],
30
+ "sg": ["gate:pdpa-dpo"],
31
+ };
32
+ const JURISDICTION_LAWS = {
33
+ "eu": ["GDPR (EU) 2016/679", "EU AI Act 2024/1689", "NIS2 Directive 2022/2555", "ePrivacy Directive"],
34
+ "us": ["FTC Act § 5", "COPPA (if under-13)", "US state privacy laws (VA CDPA · TX TDPSA · FL FDBR · CO CPA · CT CTDPA)"],
35
+ "us-ca": ["CCPA / CPRA", "California AG enforcement", "CPPA rulemaking"],
36
+ "uk": ["UK GDPR", "DPA 2018", "ICO guidance", "FCA Consumer Duty (if fintech)"],
37
+ "in": ["DPDPA 2023 (Digital Personal Data Protection Act)", "IT Act 2000 § 43A", "SPDI Rules 2011", "RBI data localisation (if fintech)"],
38
+ "br": ["LGPD (Lei 13.709/2018)", "ANPD resolutions", "Marco Civil da Internet"],
39
+ "au": ["Privacy Act 1988 (Cth)", "Australian Privacy Principles (APPs)", "CDR (if fintech)", "OAIC enforcement"],
40
+ "sg": ["PDPA 2012 (amended 2021)", "MAS TRM Guidelines (if fintech)", "PDPC Advisory Guidelines"],
41
+ };
42
+ // ── Signal dictionary ─────────────────────────────────────────────────────
43
+ export const JURISDICTION_SIGNALS = {
44
+ "eu": {
45
+ keywords: [
46
+ // Legal / regulatory terms
47
+ "gdpr", "dsgvo", "rgpd", "data protection officer", "dpo",
48
+ "right to erasure", "right to be forgotten", "data subject request",
49
+ "article 6", "article 9", "legitimate interest", "lawful basis",
50
+ "privacy by design", "privacy notice", "cookie consent",
51
+ "eu ai act", "eu users", "eu customers", "european union",
52
+ "eu data residency", "eu-west", "eu-central",
53
+ // NIS2 / DORA
54
+ "nis2", "dora ict risk", "dora compliance",
55
+ // Locales / markets
56
+ "german users", "french users", "dutch users", "austrian",
57
+ "italian users", "spanish users", "polish users",
58
+ ],
59
+ },
60
+ "us": {
61
+ keywords: [
62
+ "ftc", "ftc act", "us users", "us customers", "united states",
63
+ "american users", "coppa", "hipaa",
64
+ "virginia cdpa", "texas tdpsa", "florida fdbr", "colorado cpa",
65
+ "connecticut ctdpa", "us state privacy", "us privacy law",
66
+ ],
67
+ },
68
+ "us-ca": {
69
+ keywords: [
70
+ "ccpa", "cpra", "california consumer privacy",
71
+ "california privacy rights", "cppa", "california residents",
72
+ "california users", "do not sell", "opt-out of sale",
73
+ "data subject rights california", "dsr california",
74
+ ],
75
+ },
76
+ "uk": {
77
+ keywords: [
78
+ "uk gdpr", "information commissioner", "dpa 2018",
79
+ "uk users", "uk customers", "united kingdom", "british users",
80
+ "fca consumer duty", "uk ai regulation",
81
+ ],
82
+ },
83
+ "in": {
84
+ keywords: [
85
+ // Data protection
86
+ "dpdpa", "digital personal data protection", "india data",
87
+ "india users", "indian users", "bharat", "meity",
88
+ // Fintech / telecom
89
+ "rbi data localisation", "rbi circular", "npci", "sebi",
90
+ "india data residency",
91
+ ],
92
+ },
93
+ "br": {
94
+ keywords: [
95
+ "lgpd", "lei 13709", "anpd", "brazil users", "brazil customers",
96
+ "brazilian users", "brasil", "data encarregado", "dpo brazil",
97
+ "lgpd compliance",
98
+ ],
99
+ },
100
+ "au": {
101
+ keywords: [
102
+ "privacy act 1988", "australian privacy principles", "app principles",
103
+ "oaic", "australia users", "australian users",
104
+ "consumer data right", "notifiable data breach", "ndb scheme",
105
+ "australia data residency",
106
+ ],
107
+ },
108
+ "sg": {
109
+ keywords: [
110
+ "pdpa", "pdpc", "singapore users", "singaporean users",
111
+ "mas guidelines", "mas tpm", "singpass", "myinfo",
112
+ "singapore data residency",
113
+ ],
114
+ },
115
+ };
116
+ // ── Public API ─────────────────────────────────────────────────────────────
117
+ /** Return jurisdictions whose signals match the detection result. */
118
+ export function suggestJurisdictions(d) {
119
+ const matches = [];
120
+ const kwLower = d.readmeKeywords.map((k) => k.toLowerCase());
121
+ for (const code of Object.keys(JURISDICTION_SIGNALS)) {
122
+ const { keywords } = JURISDICTION_SIGNALS[code];
123
+ const matchedKeywords = keywords.filter((kw) => kwLower.includes(kw));
124
+ if (matchedKeywords.length === 0)
125
+ continue;
126
+ matches.push({
127
+ jurisdiction: code,
128
+ reviewers: JURISDICTION_REVIEWERS[code],
129
+ signals: matchedKeywords.slice(0, 8),
130
+ humanGates: JURISDICTION_GATES[code],
131
+ laws: JURISDICTION_LAWS[code],
132
+ });
133
+ }
134
+ matches.sort((a, b) => a.jurisdiction.localeCompare(b.jurisdiction));
135
+ return matches;
136
+ }
137
+ /** Flatten matched jurisdictions to unique sorted reviewer names. */
138
+ export function suggestJurisdictionReviewers(d) {
139
+ const all = new Set();
140
+ for (const m of suggestJurisdictions(d))
141
+ for (const r of m.reviewers)
142
+ all.add(r);
143
+ return Array.from(all).sort();
144
+ }
145
+ /** Flatten matched jurisdictions to unique sorted gate ids. */
146
+ export function suggestJurisdictionGates(d) {
147
+ const all = new Set();
148
+ for (const m of suggestJurisdictions(d))
149
+ for (const g of m.humanGates)
150
+ all.add(g);
151
+ return Array.from(all).sort();
152
+ }
153
+ /** Registry of all known jurisdiction codes — useful for /doctor. */
154
+ export function listJurisdictions() {
155
+ return Object.keys(JURISDICTION_SIGNALS).sort();
156
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.14.0",
3
+ "version": "2.16.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",