@vibekiln/cutline-mcp-cli 0.2.0 → 0.3.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.
@@ -27,7 +27,7 @@ const SERVER_NAMES = [
27
27
  'output',
28
28
  'integrations',
29
29
  ];
30
- const AUDIT_DIMENSIONS = ['engineering', 'security', 'reliability', 'scalability'];
30
+ const AUDIT_DIMENSIONS = ['engineering', 'security', 'reliability', 'scalability', 'compliance'];
31
31
  async function detectTier(options) {
32
32
  const refreshToken = await getRefreshToken();
33
33
  if (!refreshToken)
package/dist/index.js CHANGED
@@ -55,7 +55,7 @@ program
55
55
  .option('--skip-login', 'Skip authentication (use existing credentials)')
56
56
  .option('--project-root <path>', 'Project root directory for IDE rules (default: cwd)')
57
57
  .option('--hide-audit-dimension <name>', 'Hide one audit dimension in surfaced code audit output (repeatable)', (value, prev) => [...prev, value], [])
58
- .option('--hide-audit-dimensions <csv>', 'Hide multiple audit dimensions (comma-separated: engineering,security,reliability,scalability)')
58
+ .option('--hide-audit-dimensions <csv>', 'Hide multiple audit dimensions (comma-separated: engineering,security,reliability,scalability,compliance)')
59
59
  .action((opts) => setupCommand({
60
60
  staging: opts.staging,
61
61
  skipLogin: opts.skipLogin,
@@ -287,7 +287,7 @@ async function exchangeRefreshToken(refreshToken, firebaseApiKey, maxRetries = 3
287
287
  }
288
288
  throw lastError || new Error("Token exchange failed after retries");
289
289
  }
290
- var AUDIT_DIMENSIONS = ["engineering", "security", "reliability", "scalability"];
290
+ var AUDIT_DIMENSIONS = ["engineering", "security", "reliability", "scalability", "compliance"];
291
291
  function readLocalCutlineConfig() {
292
292
  try {
293
293
  const configPath = path.join(os.homedir(), ".cutline-mcp", "config.json");
@@ -565,7 +565,8 @@ function computeGraphMetrics(entities, edges, constraints, bindings, conflicts,
565
565
  gdpr: "GDPR/CCPA",
566
566
  owasp: "OWASP LLM Top 10",
567
567
  glba: "GLBA",
568
- ferpa: "FERPA/COPPA"
568
+ ferpa: "FERPA/COPPA",
569
+ ios: "iOS App Store"
569
570
  };
570
571
  const detectedFrameworks = /* @__PURE__ */ new Set();
571
572
  for (const c of constraints) {
@@ -879,7 +880,8 @@ function computeGenericGraphMetrics(entities, edges, constraints, bindings) {
879
880
  gdpr: "GDPR/CCPA",
880
881
  owasp: "OWASP LLM Top 10",
881
882
  glba: "GLBA",
882
- ferpa: "FERPA/COPPA"
883
+ ferpa: "FERPA/COPPA",
884
+ ios: "iOS App Store"
883
885
  };
884
886
  const detectedFrameworks = /* @__PURE__ */ new Set();
885
887
  for (const c of constraints) {
@@ -75,13 +75,13 @@ import {
75
75
  upsertEntities,
76
76
  upsertNodes,
77
77
  validateRequestSize
78
- } from "./chunk-LI4AZPSJ.js";
78
+ } from "./chunk-6Y3AEXE3.js";
79
79
  import {
80
80
  GraphTraverser,
81
81
  computeGenericGraphMetrics,
82
82
  computeMetricsFromGraph,
83
83
  detectConstraintConflicts
84
- } from "./chunk-UBBAYTW3.js";
84
+ } from "./chunk-IDSVMCGM.js";
85
85
 
86
86
  // ../mcp/dist/mcp/src/cutline-server.js
87
87
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -416,6 +416,21 @@ var PATH_PATTERNS = [
416
416
  categories: ["compliance", "security"],
417
417
  domain: "fedramp",
418
418
  priority: "high"
419
+ },
420
+ {
421
+ patterns: [
422
+ /\/ios/i,
423
+ /\/swift/i,
424
+ /\/storekit/i,
425
+ /\/appstore/i,
426
+ /\/testflight/i,
427
+ /\.swift$/i,
428
+ /Info\.plist$/i
429
+ ],
430
+ keywords: ["ios", "app-store", "storekit", "iap", "testflight", "swift", "mobile"],
431
+ categories: ["compliance", "security", "risk"],
432
+ domain: "ios_app_store",
433
+ priority: "high"
419
434
  }
420
435
  ];
421
436
  var CODE_PATTERNS = [
@@ -590,6 +605,20 @@ var CODE_PATTERNS = [
590
605
  keywords: ["csa", "ccm", "cloud", "aws", "gcp", "azure", "cloud-security"],
591
606
  categories: ["compliance", "security"],
592
607
  domain: "csa_ccm"
608
+ },
609
+ {
610
+ patterns: [
611
+ /StoreKit/i,
612
+ /SKPaymentQueue/i,
613
+ /SKProductsRequest/i,
614
+ /ASAuthorizationAppleID/i,
615
+ /UIApplicationOpenSettingsURLString/i,
616
+ /ATTrackingManager/i,
617
+ /\.swift$/i
618
+ ],
619
+ keywords: ["ios", "app-store", "storekit", "iap", "apple-signin", "tracking-consent"],
620
+ categories: ["compliance", "security"],
621
+ domain: "ios_app_store"
593
622
  }
594
623
  ];
595
624
  function analyzeFilePaths(paths) {
@@ -2978,7 +3007,8 @@ var FRAMEWORK_ID_PREFIXES = {
2978
3007
  gdpr: "GDPR/CCPA",
2979
3008
  owasp: "OWASP LLM Top 10",
2980
3009
  glba: "GLBA",
2981
- ferpa: "FERPA/COPPA"
3010
+ ferpa: "FERPA/COPPA",
3011
+ ios: "iOS App Store"
2982
3012
  };
2983
3013
  function resolveFramework(constraintId) {
2984
3014
  if (!constraintId.startsWith("constraint:blueprint:"))
@@ -5406,6 +5436,53 @@ var BLUEPRINT_RULES = [
5406
5436
  framework: "ferpa_coppa"
5407
5437
  }
5408
5438
  ]
5439
+ },
5440
+ // ── iOS App Store Review Guidelines (mobile iOS apps) ──────────────────────
5441
+ {
5442
+ trigger: (eco, ctx) => {
5443
+ const iosSignals = /ios|swift|swiftui|xcode|uikit|storekit|appstore|testflight|cocoapods|xcframework/i;
5444
+ const hasLang = eco.languages.some((l) => /swift|objective-c|objc/i.test(l));
5445
+ const hasFramework = eco.frameworks.some((f) => iosSignals.test(f));
5446
+ const hasDep = eco.all_dependencies.some((d) => iosSignals.test(d));
5447
+ const descMatch = ctx?.productDescription ? /\b(ios|iphone|ipad|app\s*store|testflight|storekit|in-app purchase|apple sign in)\b/i.test(ctx.productDescription) : false;
5448
+ const entityMatch = ctx?.existingEntityNames?.some((n) => /\b(ios|mobile|iphone|ipad|app store|iap|storekit)\b/i.test(n)) ?? false;
5449
+ return hasLang || hasFramework || hasDep || descMatch || entityMatch;
5450
+ },
5451
+ constraints: [
5452
+ {
5453
+ id_suffix: "ios_app_store_privacy_disclosure",
5454
+ category: "compliance",
5455
+ summary: "[iOS App Store 5.1] Apps collecting user data MUST provide accurate privacy disclosures and clear in-app data handling flows.",
5456
+ keywords: ["ios", "app-store", "privacy", "disclosure", "tracking", "app-privacy"],
5457
+ severity: "critical",
5458
+ action: "Document data collection in App Privacy labels and align runtime behavior. Gate tracking behind explicit consent where required.",
5459
+ checklist_ref: "IOS-5.1",
5460
+ file_patterns: ["**/ios/**", "**/*.swift", "**/privacy*", "**/tracking/**", "**/analytics/**"],
5461
+ framework: "ios_app_store"
5462
+ },
5463
+ {
5464
+ id_suffix: "ios_app_store_iap_policy",
5465
+ category: "compliance",
5466
+ summary: "[iOS App Store 3.1] Digital goods/services sold in-app MUST use Apple's In-App Purchase flows where required.",
5467
+ keywords: ["ios", "app-store", "iap", "storekit", "payments", "digital-goods"],
5468
+ severity: "warning",
5469
+ action: "Use StoreKit for digital purchases in iOS app surfaces. Avoid bypass payment links that violate App Store rules.",
5470
+ checklist_ref: "IOS-3.1",
5471
+ file_patterns: ["**/ios/**", "**/*.swift", "**/billing/**", "**/payment/**", "**/storekit/**"],
5472
+ framework: "ios_app_store"
5473
+ },
5474
+ {
5475
+ id_suffix: "ios_app_store_account_deletion",
5476
+ category: "compliance",
5477
+ summary: "[iOS App Store 5.1.1(v)] If account creation exists, apps MUST provide in-app account deletion with data handling consistent with policy.",
5478
+ keywords: ["ios", "app-store", "account-deletion", "user-account", "privacy-rights"],
5479
+ severity: "warning",
5480
+ action: "Expose account deletion in-app for iOS users and ensure backend deletion flow is implemented and verifiable.",
5481
+ checklist_ref: "IOS-5.1.1",
5482
+ file_patterns: ["**/ios/**", "**/*.swift", "**/api/account*", "**/api/user*", "**/settings/**"],
5483
+ framework: "ios_app_store"
5484
+ }
5485
+ ]
5409
5486
  }
5410
5487
  ];
5411
5488
  function buildBlueprintConstraints(ecosystem, context) {
@@ -5505,6 +5582,7 @@ Flag if the codebase contains signals that would require specific compliance fra
5505
5582
  - **OWASP LLM**: OpenAI, Anthropic, LangChain, vector DBs (Pinecone, Weaviate), RAG pipelines, AI agents
5506
5583
  - **GLBA**: Plaid, banking SDKs, KYC/AML, lending/mortgage/wealth management code
5507
5584
  - **FERPA/COPPA**: EdTech integrations (Clever, Canvas), student/minor data, classroom/school references
5585
+ - **iOS App Store**: iOS/Swift codepaths, App Store/TestFlight distribution, StoreKit/IAP, mobile app privacy policies
5508
5586
 
5509
5587
  For each detected signal, note:
5510
5588
  - H1. Which framework(s) apply and why
@@ -5552,7 +5630,7 @@ Return a JSON object with exactly these fields:
5552
5630
  - referenceClasses (string[]): Security frameworks or standards that apply (e.g., "OWASP Top 10 2021", "SOC 2 Type II").
5553
5631
  - constraints (object?): Resource constraints \u2014 team, budget_usd, deadline_days, must_ship_scope.
5554
5632
  - checklist_summary (object): Keys are checklist IDs (A1-A8, B1-B6, C1-C7, D1-D8, E1-E4, F1-F3, G-*, H1-H3, I1-I8, J1-J6, K1-K8), values are "pass"|"fail"|"warn"|"not_applicable". This forces systematic coverage.
5555
- - compliance_signals (array of {framework: "pci_dss"|"hipaa"|"fedramp"|"gdpr_ccpa"|"owasp_llm"|"glba"|"ferpa_coppa"|"csa_ccm", signal: string, confidence: number}?): Detected compliance framework signals. Return [] if none.
5633
+ - compliance_signals (array of {framework: "pci_dss"|"hipaa"|"fedramp"|"gdpr_ccpa"|"owasp_llm"|"glba"|"ferpa_coppa"|"csa_ccm"|"ios_app_store", signal: string, confidence: number}?): Detected compliance framework signals. Return [] if none.
5556
5634
 
5557
5635
  Be concrete and specific. Reference file paths and line numbers where possible. If a checklist item cannot be assessed from the provided files, mark it "not_applicable" and note why. Cover ALL sections A through K.`;
5558
5636
  var FULL_SYSTEM_PROMPT = `You are a product analyst reviewing a codebase. Given file contents, an ecosystem fingerprint, and existing constraints, extract structured product context.
@@ -6157,13 +6235,15 @@ async function seedBlueprintConstraints(productId, ecosystem, deps, blueprintCon
6157
6235
  const FRAMEWORK_LABELS = {
6158
6236
  baseline: "Security Baseline",
6159
6237
  soc2: "SOC 2",
6238
+ csa_ccm: "CSA Controls Matrix",
6160
6239
  pci_dss: "PCI-DSS",
6161
6240
  hipaa: "HIPAA",
6162
6241
  fedramp: "FedRAMP",
6163
6242
  gdpr_ccpa: "GDPR/CCPA",
6164
6243
  owasp_llm: "OWASP LLM Top 10",
6165
6244
  glba: "GLBA",
6166
- ferpa_coppa: "FERPA/COPPA"
6245
+ ferpa_coppa: "FERPA/COPPA",
6246
+ ios_app_store: "iOS App Store"
6167
6247
  };
6168
6248
  const newEntities = [];
6169
6249
  const newEdges = [];
@@ -6979,10 +7059,15 @@ function formatAuditOutput(result, reportId, publicSiteUrl = "https://thecutline
6979
7059
  return "reliability";
6980
7060
  if (["scalability", "performance"].includes(c))
6981
7061
  return "scalability";
7062
+ if (["compliance"].includes(c))
7063
+ return "compliance";
6982
7064
  if (["code_quality", "general"].includes(c))
6983
7065
  return "engineering";
6984
7066
  return "security";
6985
7067
  };
7068
+ const hasComplianceFrameworks = result.frameworksLoaded.length > 0;
7069
+ const complianceCurrent = hasComplianceFrameworks ? Math.round((m.nfr_coverage?.compliance ?? 0) * 100) : void 0;
7070
+ const compliancePrevious = hasComplianceFrameworks ? Math.round((p?.nfr_coverage?.compliance ?? 0) * 100) : void 0;
6986
7071
  const lines = [
6987
7072
  `# Cutline Code Audit`,
6988
7073
  ``,
@@ -7016,12 +7101,19 @@ function formatAuditOutput(result, reportId, publicSiteUrl = "https://thecutline
7016
7101
  label: "Scalability",
7017
7102
  current: m.scalability_readiness_pct ?? 0,
7018
7103
  previous: p?.scalability_readiness_pct
7104
+ },
7105
+ {
7106
+ key: "compliance",
7107
+ label: "Compliance",
7108
+ current: complianceCurrent,
7109
+ previous: compliancePrevious,
7110
+ na: !hasComplianceFrameworks
7019
7111
  }
7020
7112
  ].filter((row) => !hiddenSet.has(row.key));
7021
7113
  lines.push(``, `## Readiness Scores`, ``, `| Pillar | Score |${isRescan ? " Change |" : ""}`, `|--------|-------|${isRescan ? "--------|" : ""}`);
7022
7114
  if (scoreRows.length > 0) {
7023
7115
  for (const row of scoreRows) {
7024
- lines.push(`| ${row.label} | ${row.current}% |${isRescan ? deltaStr(row.current, row.previous) + " |" : ""}`);
7116
+ lines.push(`| ${row.label} | ${row.na ? "N/A" : `${row.current ?? 0}%`} |${isRescan ? row.na ? " (n/a) |" : deltaStr(row.current, row.previous) + " |" : ""}`);
7025
7117
  }
7026
7118
  lines.push(``);
7027
7119
  } else {
@@ -8279,6 +8371,8 @@ Why AI: ${idea.whyAI}`
8279
8371
  return "reliability";
8280
8372
  if (["scalability", "performance"].includes(c))
8281
8373
  return "scalability";
8374
+ if (["compliance"].includes(c))
8375
+ return "compliance";
8282
8376
  if (["code_quality", "general"].includes(c))
8283
8377
  return "engineering";
8284
8378
  return "security";
@@ -8332,6 +8426,9 @@ Why AI: ${idea.whyAI}`
8332
8426
  if (!hiddenSet.has("scalability")) {
8333
8427
  reportMetrics.scalability_readiness_pct = result.metrics.scalability_readiness_pct ?? 0;
8334
8428
  }
8429
+ if (!hiddenSet.has("compliance")) {
8430
+ reportMetrics.compliance_readiness_pct = result.frameworksLoaded.length > 0 ? Math.round((result.metrics.nfr_coverage?.compliance ?? 0) * 100) : null;
8431
+ }
8335
8432
  const visibleFindings = result.gatedGapDetails.filter((f) => !hiddenSet.has(inferFindingDimension(f.category)));
8336
8433
  const saved = await saveScanReport({
8337
8434
  metrics: reportMetrics,
@@ -9011,7 +9108,8 @@ Meta: ${JSON.stringify(output.meta)}` }
9011
9108
  gdpr: "GDPR/CCPA",
9012
9109
  owasp: "OWASP LLM Top 10",
9013
9110
  glba: "GLBA",
9014
- ferpa: "FERPA/COPPA"
9111
+ ferpa: "FERPA/COPPA",
9112
+ ios: "iOS App Store"
9015
9113
  };
9016
9114
  const formattedConstraints = topConstraints.map((c) => {
9017
9115
  const framework = detectFramework2(c.id);
@@ -10001,7 +10099,7 @@ ${JSON.stringify(metrics, null, 2)}` }
10001
10099
  getAllNodes(product_id),
10002
10100
  getAllBindings(product_id)
10003
10101
  ]);
10004
- const { computeMetricsFromGraph: computeMetricsFromGraph2 } = await import("./graph-metrics-DCNR7JZN.js");
10102
+ const { computeMetricsFromGraph: computeMetricsFromGraph2 } = await import("./graph-metrics-KLHCMDFT.js");
10005
10103
  const updatedMetrics = computeMetricsFromGraph2(rgrEntities, rgrEdges, rgrConstraints, rgrBindings, updatedPhases);
10006
10104
  await updateGraphMetadata(product_id, {
10007
10105
  ...meta ?? {
@@ -10427,7 +10525,8 @@ Meta: ${JSON.stringify({
10427
10525
  gdpr_ccpa: "GDPR/CCPA",
10428
10526
  owasp_llm: "OWASP LLM Top 10",
10429
10527
  glba: "GLBA",
10430
- ferpa_coppa: "FERPA/COPPA"
10528
+ ferpa_coppa: "FERPA/COPPA",
10529
+ ios_app_store: "iOS App Store"
10431
10530
  };
10432
10531
  const names = result.frameworksLoaded.map((f) => fwLabels[f] || f);
10433
10532
  sections.push(`- Compliance frameworks loaded: **${names.join(", ")}**`);
@@ -78,7 +78,7 @@ import {
78
78
  upsertEdges,
79
79
  upsertEntities,
80
80
  upsertNodes
81
- } from "./chunk-LI4AZPSJ.js";
81
+ } from "./chunk-6Y3AEXE3.js";
82
82
  export {
83
83
  addEdges,
84
84
  addEntity,
@@ -14,7 +14,7 @@ import {
14
14
  requirePremiumWithAutoAuth,
15
15
  updateExplorationSession,
16
16
  validateRequestSize
17
- } from "./chunk-LI4AZPSJ.js";
17
+ } from "./chunk-6Y3AEXE3.js";
18
18
 
19
19
  // ../mcp/dist/mcp/src/exploration-server.js
20
20
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -3,7 +3,7 @@ import {
3
3
  computeGenericGraphMetrics,
4
4
  computeGraphMetrics,
5
5
  computeMetricsFromGraph
6
- } from "./chunk-UBBAYTW3.js";
6
+ } from "./chunk-IDSVMCGM.js";
7
7
  export {
8
8
  applyGenericPrior,
9
9
  computeGenericGraphMetrics,
@@ -13,7 +13,7 @@ import {
13
13
  requirePremiumWithAutoAuth,
14
14
  validateAuth,
15
15
  validateRequestSize
16
- } from "./chunk-LI4AZPSJ.js";
16
+ } from "./chunk-6Y3AEXE3.js";
17
17
 
18
18
  // ../mcp/dist/mcp/src/integrations-server.js
19
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -13,7 +13,7 @@ import {
13
13
  mapErrorToMcp,
14
14
  requirePremiumWithAutoAuth,
15
15
  validateRequestSize
16
- } from "./chunk-LI4AZPSJ.js";
16
+ } from "./chunk-6Y3AEXE3.js";
17
17
 
18
18
  // ../mcp/dist/mcp/src/output-server.js
19
19
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -27,7 +27,7 @@ import {
27
27
  updatePremortem,
28
28
  validateAuth,
29
29
  validateRequestSize
30
- } from "./chunk-LI4AZPSJ.js";
30
+ } from "./chunk-6Y3AEXE3.js";
31
31
 
32
32
  // ../mcp/dist/mcp/src/premortem-server.js
33
33
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -21,7 +21,7 @@ import {
21
21
  requirePremiumWithAutoAuth,
22
22
  validateAuth,
23
23
  validateRequestSize
24
- } from "./chunk-LI4AZPSJ.js";
24
+ } from "./chunk-6Y3AEXE3.js";
25
25
 
26
26
  // ../mcp/dist/mcp/src/tools-server.js
27
27
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibekiln/cutline-mcp-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "CLI and MCP servers for Cutline — authenticate, then run constraint-aware MCP servers in Cursor or any MCP client.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",