@contentrain/mcp 0.3.1 → 1.0.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.
Files changed (115) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +147 -238
  3. package/dist/apply-manager-CaTuu7Lj.mjs +751 -0
  4. package/dist/apply-manager-CaTuu7Lj.mjs.map +1 -0
  5. package/dist/astro-parser-RofKmKQi.mjs +166 -0
  6. package/dist/astro-parser-RofKmKQi.mjs.map +1 -0
  7. package/dist/branch-lifecycle-DB6sgeJi.mjs +97 -0
  8. package/dist/branch-lifecycle-DB6sgeJi.mjs.map +1 -0
  9. package/dist/chunk-BEJ448es.mjs +35 -0
  10. package/dist/compiler-rIC4ETHv.mjs +44509 -0
  11. package/dist/compiler-rIC4ETHv.mjs.map +1 -0
  12. package/dist/compiler-sfc.cjs-BbD04rn_.mjs +50279 -0
  13. package/dist/compiler-sfc.cjs-BbD04rn_.mjs.map +1 -0
  14. package/dist/config-CPlhDwsv.mjs +27 -0
  15. package/dist/config-CPlhDwsv.mjs.map +1 -0
  16. package/dist/context-yh3cuw5N.mjs +46 -0
  17. package/dist/context-yh3cuw5N.mjs.map +1 -0
  18. package/dist/core/apply-manager.d.mts +144 -0
  19. package/dist/core/apply-manager.d.mts.map +1 -0
  20. package/dist/core/apply-manager.mjs +6 -0
  21. package/dist/core/config.d.mts +8 -0
  22. package/dist/core/config.d.mts.map +1 -0
  23. package/dist/core/config.mjs +2 -0
  24. package/dist/core/content-manager.d.mts +53 -0
  25. package/dist/core/content-manager.d.mts.map +1 -0
  26. package/dist/core/content-manager.mjs +2 -0
  27. package/dist/core/context.d.mts +13 -0
  28. package/dist/core/context.d.mts.map +1 -0
  29. package/dist/core/context.mjs +3 -0
  30. package/dist/core/graph-builder.d.mts +12 -0
  31. package/dist/core/graph-builder.d.mts.map +1 -0
  32. package/dist/core/graph-builder.mjs +2 -0
  33. package/dist/core/meta-manager.d.mts +14 -0
  34. package/dist/core/meta-manager.d.mts.map +1 -0
  35. package/dist/core/meta-manager.mjs +2 -0
  36. package/dist/core/model-manager.d.mts +44 -0
  37. package/dist/core/model-manager.d.mts.map +1 -0
  38. package/dist/core/model-manager.mjs +2 -0
  39. package/dist/core/scan-config.d.mts +24 -0
  40. package/dist/core/scan-config.d.mts.map +1 -0
  41. package/dist/core/scan-config.mjs +2 -0
  42. package/dist/core/scanner.d.mts +25 -0
  43. package/dist/core/scanner.d.mts.map +1 -0
  44. package/dist/core/scanner.mjs +3 -0
  45. package/dist/core/validator.d.mts +23 -0
  46. package/dist/core/validator.d.mts.map +1 -0
  47. package/dist/core/validator.mjs +3 -0
  48. package/dist/detect-C8XmJ4S6.mjs +362 -0
  49. package/dist/detect-C8XmJ4S6.mjs.map +1 -0
  50. package/dist/fs-BbuGnVcG.mjs +52 -0
  51. package/dist/fs-BbuGnVcG.mjs.map +1 -0
  52. package/dist/git/branch-lifecycle.d.mts +28 -0
  53. package/dist/git/branch-lifecycle.d.mts.map +1 -0
  54. package/dist/git/branch-lifecycle.mjs +2 -0
  55. package/dist/git/transaction.d.mts +25 -0
  56. package/dist/git/transaction.d.mts.map +1 -0
  57. package/dist/git/transaction.mjs +4 -0
  58. package/dist/graph-builder-fPrDDwnu.mjs +162 -0
  59. package/dist/graph-builder-fPrDDwnu.mjs.map +1 -0
  60. package/dist/id-BdD4HvMY.mjs +12 -0
  61. package/dist/id-BdD4HvMY.mjs.map +1 -0
  62. package/dist/index.d.mts +1 -359
  63. package/dist/index.mjs +15 -2161
  64. package/dist/index.mjs.map +1 -1
  65. package/dist/meta-manager-CECrfsKm.mjs +53 -0
  66. package/dist/meta-manager-CECrfsKm.mjs.map +1 -0
  67. package/dist/model-manager-BcWWu5l2.mjs +963 -0
  68. package/dist/model-manager-BcWWu5l2.mjs.map +1 -0
  69. package/dist/node-Cbq5eR5i.mjs +300 -0
  70. package/dist/node-Cbq5eR5i.mjs.map +1 -0
  71. package/dist/scan-config-AJGxCdNd.mjs +159 -0
  72. package/dist/scan-config-AJGxCdNd.mjs.map +1 -0
  73. package/dist/scanner-BdTiv8sw.mjs +619 -0
  74. package/dist/scanner-BdTiv8sw.mjs.map +1 -0
  75. package/dist/serializer-Dueih-i2.mjs +33 -0
  76. package/dist/serializer-Dueih-i2.mjs.map +1 -0
  77. package/dist/server-CTcDpxwW.mjs +1861 -0
  78. package/dist/server-CTcDpxwW.mjs.map +1 -0
  79. package/dist/server.d.mts +7 -0
  80. package/dist/server.d.mts.map +1 -0
  81. package/dist/server.mjs +11 -0
  82. package/dist/source-map-generator-DpO-ejrt.mjs +893 -0
  83. package/dist/source-map-generator-DpO-ejrt.mjs.map +1 -0
  84. package/dist/svelte-parser-COTNG92w.mjs +225 -0
  85. package/dist/svelte-parser-COTNG92w.mjs.map +1 -0
  86. package/dist/templates/index.d.mts +8 -0
  87. package/dist/templates/index.d.mts.map +1 -0
  88. package/dist/templates/index.mjs +2 -0
  89. package/dist/templates-3HWi-PTu.mjs +824 -0
  90. package/dist/templates-3HWi-PTu.mjs.map +1 -0
  91. package/dist/transaction-BsECnmL5.mjs +128 -0
  92. package/dist/transaction-BsECnmL5.mjs.map +1 -0
  93. package/dist/tsx-parser-Bf8Firrq.mjs +2 -0
  94. package/dist/tsx-parser-CYVyBWjn.mjs +234 -0
  95. package/dist/tsx-parser-CYVyBWjn.mjs.map +1 -0
  96. package/dist/util/detect.d.mts +20 -0
  97. package/dist/util/detect.d.mts.map +1 -0
  98. package/dist/util/detect.mjs +2 -0
  99. package/dist/util/fs.d.mts +12 -0
  100. package/dist/util/fs.d.mts.map +1 -0
  101. package/dist/util/fs.mjs +2 -0
  102. package/dist/util/id.d.mts +6 -0
  103. package/dist/util/id.d.mts.map +1 -0
  104. package/dist/util/id.mjs +2 -0
  105. package/dist/util/serializer.d.mts +14 -0
  106. package/dist/util/serializer.d.mts.map +1 -0
  107. package/dist/util/serializer.mjs +2 -0
  108. package/dist/validator-ku84AyFr.mjs +755 -0
  109. package/dist/validator-ku84AyFr.mjs.map +1 -0
  110. package/dist/vue-parser-CjS4YAoQ.mjs +225 -0
  111. package/dist/vue-parser-CjS4YAoQ.mjs.map +1 -0
  112. package/package.json +107 -43
  113. package/dist/fs-D83-Ii_y.mjs +0 -75
  114. package/dist/fs-D83-Ii_y.mjs.map +0 -1
  115. package/dist/index.d.mts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates-3HWi-PTu.mjs","names":[],"sources":["../src/templates/blog.ts","../src/templates/landing.ts","../src/templates/docs.ts","../src/templates/ecommerce.ts","../src/templates/saas.ts","../src/templates/i18n.ts","../src/templates/mobile.ts","../src/templates/index.ts"],"sourcesContent":["import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const blogTemplate: ScaffoldTemplate = {\n id: 'blog',\n models: [\n {\n id: 'blog-post',\n name: 'Blog Post',\n kind: 'document',\n domain: 'blog',\n i18n: true,\n fields: {\n title: { type: 'string', required: true, max: 120 },\n slug: { type: 'slug', required: true, unique: true },\n excerpt: { type: 'text', max: 280 },\n cover: { type: 'image' },\n author: { type: 'relation', model: 'authors', required: true },\n category: { type: 'relation', model: 'categories' },\n tags: { type: 'array', items: 'string' },\n published_at: { type: 'datetime' },\n },\n },\n {\n id: 'categories',\n name: 'Categories',\n kind: 'collection',\n domain: 'blog',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n description: { type: 'text' },\n },\n },\n {\n id: 'authors',\n name: 'Authors',\n kind: 'collection',\n domain: 'blog',\n i18n: false,\n fields: {\n name: { type: 'string', required: true },\n email: { type: 'email' },\n bio: { type: 'text' },\n avatar: { type: 'image' },\n social: {\n type: 'object',\n fields: {\n twitter: { type: 'url' },\n linkedin: { type: 'url' },\n github: { type: 'url' },\n },\n },\n },\n },\n ],\n sample_content: {\n categories: {\n en: {\n 'cat-engineering': { name: 'Engineering', slug: 'engineering', description: 'Technical deep dives' },\n 'cat-product': { name: 'Product', slug: 'product', description: 'Product updates and news' },\n },\n },\n authors: {\n data: {\n 'author-1': { name: 'Team', email: 'team@example.com', bio: 'The team behind the product' },\n },\n },\n },\n vocabulary: {\n 'read-more': { en: 'Read More' },\n 'published-on': { en: 'Published on' },\n 'by-author': { en: 'By' },\n 'categories': { en: 'Categories' },\n 'tags': { en: 'Tags' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const landingTemplate: ScaffoldTemplate = {\n id: 'landing',\n models: [\n {\n id: 'hero',\n name: 'Hero Section',\n kind: 'singleton',\n domain: 'marketing',\n i18n: true,\n fields: {\n title: { type: 'string', required: true, max: 120 },\n subtitle: { type: 'text', max: 280 },\n cta_text: { type: 'string' },\n cta_url: { type: 'url' },\n background: { type: 'image' },\n },\n },\n {\n id: 'features',\n name: 'Features Section',\n kind: 'singleton',\n domain: 'marketing',\n i18n: true,\n fields: {\n title: { type: 'string', required: true },\n subtitle: { type: 'text' },\n items: {\n type: 'array',\n items: {\n type: 'object',\n fields: {\n title: { type: 'string', required: true },\n description: { type: 'text' },\n icon: { type: 'icon' },\n },\n },\n },\n },\n },\n {\n id: 'pricing',\n name: 'Pricing Plans',\n kind: 'collection',\n domain: 'marketing',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n price: { type: 'number', required: true },\n currency: { type: 'string', default: 'USD' },\n period: { type: 'select', options: ['monthly', 'yearly'] },\n features: { type: 'array', items: 'string' },\n highlighted: { type: 'boolean', default: false },\n },\n },\n {\n id: 'faq',\n name: 'FAQ',\n kind: 'collection',\n domain: 'marketing',\n i18n: true,\n fields: {\n question: { type: 'string', required: true },\n answer: { type: 'text', required: true },\n order: { type: 'integer' },\n },\n },\n {\n id: 'testimonials',\n name: 'Testimonials',\n kind: 'collection',\n domain: 'marketing',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n role: { type: 'string' },\n company: { type: 'string' },\n quote: { type: 'text', required: true },\n avatar: { type: 'image' },\n rating: { type: 'rating' },\n },\n },\n ],\n sample_content: {\n hero: {\n en: {\n title: 'Build something amazing',\n subtitle: 'The fastest way to launch your product',\n cta_text: 'Get Started',\n cta_url: '/signup',\n },\n },\n pricing: {\n en: {\n 'plan-free': { name: 'Free', price: 0, currency: 'USD', period: 'monthly', features: ['1 project', 'Basic support'], highlighted: false },\n 'plan-pro': { name: 'Pro', price: 29, currency: 'USD', period: 'monthly', features: ['Unlimited projects', 'Priority support', 'Advanced analytics'], highlighted: true },\n },\n },\n },\n vocabulary: {\n 'get-started': { en: 'Get Started' },\n 'learn-more': { en: 'Learn More' },\n 'per-month': { en: '/month' },\n 'most-popular': { en: 'Most Popular' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const docsTemplate: ScaffoldTemplate = {\n id: 'docs',\n models: [\n {\n id: 'doc-page',\n name: 'Documentation Page',\n kind: 'document',\n domain: 'docs',\n i18n: true,\n fields: {\n title: { type: 'string', required: true, max: 120 },\n slug: { type: 'slug', required: true, unique: true },\n category: { type: 'relation', model: 'doc-categories' },\n order: { type: 'integer' },\n excerpt: { type: 'text', max: 280 },\n },\n },\n {\n id: 'doc-categories',\n name: 'Doc Categories',\n kind: 'collection',\n domain: 'docs',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n order: { type: 'integer' },\n },\n },\n ],\n sample_content: {\n 'doc-categories': {\n en: {\n 'cat-getting-started': { name: 'Getting Started', slug: 'getting-started', order: 1 },\n 'cat-guides': { name: 'Guides', slug: 'guides', order: 2 },\n 'cat-api': { name: 'API Reference', slug: 'api', order: 3 },\n },\n },\n },\n vocabulary: {\n 'on-this-page': { en: 'On This Page' },\n 'edit-this-page': { en: 'Edit this page' },\n 'next': { en: 'Next' },\n 'previous': { en: 'Previous' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const ecommerceTemplate: ScaffoldTemplate = {\n id: 'ecommerce',\n models: [\n {\n id: 'products',\n name: 'Products',\n kind: 'collection',\n domain: 'shop',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n description: { type: 'text' },\n price: { type: 'decimal', required: true },\n currency: { type: 'string', default: 'USD' },\n image: { type: 'image' },\n category: { type: 'relation', model: 'product-categories' },\n brand: { type: 'relation', model: 'brands' },\n in_stock: { type: 'boolean', default: true },\n },\n },\n {\n id: 'product-categories',\n name: 'Product Categories',\n kind: 'collection',\n domain: 'shop',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n description: { type: 'text' },\n image: { type: 'image' },\n },\n },\n {\n id: 'brands',\n name: 'Brands',\n kind: 'collection',\n domain: 'shop',\n i18n: false,\n fields: {\n name: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n logo: { type: 'image' },\n website: { type: 'url' },\n },\n },\n ],\n sample_content: {\n 'product-categories': {\n en: {\n 'cat-electronics': { name: 'Electronics', slug: 'electronics', description: 'Electronic devices and accessories' },\n 'cat-clothing': { name: 'Clothing', slug: 'clothing', description: 'Apparel and fashion' },\n },\n },\n brands: {\n data: {\n 'brand-acme': { name: 'Acme Corp', slug: 'acme', website: 'https://example.com' },\n },\n },\n },\n vocabulary: {\n 'add-to-cart': { en: 'Add to Cart' },\n 'out-of-stock': { en: 'Out of Stock' },\n 'price': { en: 'Price' },\n 'category': { en: 'Category' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const saasTemplate: ScaffoldTemplate = {\n id: 'saas',\n models: [\n {\n id: 'hero',\n name: 'Hero Section',\n kind: 'singleton',\n domain: 'marketing',\n i18n: true,\n fields: {\n title: { type: 'string', required: true, max: 120 },\n subtitle: { type: 'text', max: 280 },\n cta_text: { type: 'string' },\n cta_url: { type: 'url' },\n background: { type: 'image' },\n },\n },\n {\n id: 'features',\n name: 'Features',\n kind: 'singleton',\n domain: 'marketing',\n i18n: true,\n fields: {\n title: { type: 'string', required: true },\n subtitle: { type: 'text' },\n items: {\n type: 'array',\n items: {\n type: 'object',\n fields: {\n title: { type: 'string', required: true },\n description: { type: 'text' },\n icon: { type: 'icon' },\n },\n },\n },\n },\n },\n {\n id: 'pricing',\n name: 'Pricing Plans',\n kind: 'collection',\n domain: 'marketing',\n i18n: true,\n fields: {\n name: { type: 'string', required: true },\n price: { type: 'number', required: true },\n currency: { type: 'string', default: 'USD' },\n period: { type: 'select', options: ['monthly', 'yearly'] },\n features: { type: 'array', items: 'string' },\n highlighted: { type: 'boolean', default: false },\n },\n },\n {\n id: 'changelog',\n name: 'Changelog',\n kind: 'document',\n domain: 'product',\n i18n: true,\n fields: {\n title: { type: 'string', required: true },\n slug: { type: 'slug', required: true, unique: true },\n version: { type: 'string' },\n published_at: { type: 'date' },\n tags: { type: 'array', items: 'string' },\n },\n },\n {\n id: 'faq',\n name: 'FAQ',\n kind: 'collection',\n domain: 'marketing',\n i18n: true,\n fields: {\n question: { type: 'string', required: true },\n answer: { type: 'text', required: true },\n order: { type: 'integer' },\n },\n },\n ],\n sample_content: {\n hero: {\n en: {\n title: 'Ship faster with our platform',\n subtitle: 'Everything you need to build, deploy, and scale',\n cta_text: 'Start Free Trial',\n cta_url: '/signup',\n },\n },\n pricing: {\n en: {\n 'plan-starter': { name: 'Starter', price: 0, currency: 'USD', period: 'monthly', features: ['Up to 3 projects', 'Community support'], highlighted: false },\n 'plan-team': { name: 'Team', price: 49, currency: 'USD', period: 'monthly', features: ['Unlimited projects', 'Priority support', 'Team collaboration'], highlighted: true },\n 'plan-enterprise': { name: 'Enterprise', price: 199, currency: 'USD', period: 'monthly', features: ['Everything in Team', 'SSO', 'SLA', 'Dedicated support'], highlighted: false },\n },\n },\n },\n vocabulary: {\n 'start-free': { en: 'Start Free Trial' },\n 'contact-sales': { en: 'Contact Sales' },\n 'per-month': { en: '/month' },\n 'changelog': { en: 'Changelog' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const i18nTemplate: ScaffoldTemplate = {\n id: 'i18n',\n models: [\n {\n id: 'navigation',\n name: 'Navigation',\n kind: 'singleton',\n domain: 'ui',\n i18n: true,\n fields: {\n brand: { type: 'string', required: true },\n items: {\n type: 'array',\n items: {\n type: 'object',\n fields: {\n label: { type: 'string', required: true },\n url: { type: 'url', required: true },\n },\n },\n },\n },\n },\n {\n id: 'form-labels',\n name: 'Form Labels',\n kind: 'singleton',\n domain: 'ui',\n i18n: true,\n fields: {\n name: { type: 'string' },\n email: { type: 'string' },\n password: { type: 'string' },\n submit: { type: 'string' },\n cancel: { type: 'string' },\n },\n },\n {\n id: 'error-messages',\n name: 'Error Messages',\n kind: 'dictionary',\n domain: 'system',\n i18n: true,\n },\n {\n id: 'app-strings',\n name: 'App Strings',\n kind: 'dictionary',\n domain: 'system',\n i18n: true,\n },\n ],\n sample_content: {\n navigation: {\n en: {\n brand: 'My App',\n items: [\n { label: 'Home', url: '/' },\n { label: 'About', url: '/about' },\n { label: 'Contact', url: '/contact' },\n ],\n },\n },\n 'form-labels': {\n en: {\n name: 'Name',\n email: 'Email',\n password: 'Password',\n submit: 'Submit',\n cancel: 'Cancel',\n },\n },\n 'error-messages': {\n en: {\n 'required-field': 'This field is required',\n 'invalid-email': 'Please enter a valid email',\n 'server-error': 'Something went wrong, please try again',\n },\n },\n 'app-strings': {\n en: {\n 'welcome': 'Welcome',\n 'loading': 'Loading...',\n 'no-results': 'No results found',\n },\n },\n },\n vocabulary: {\n 'language': { en: 'Language' },\n 'switch-locale': { en: 'Switch language' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\n\nexport const mobileTemplate: ScaffoldTemplate = {\n id: 'mobile',\n models: [\n {\n id: 'app-strings',\n name: 'App Strings',\n kind: 'dictionary',\n domain: 'system',\n i18n: true,\n },\n {\n id: 'error-messages',\n name: 'Error Messages',\n kind: 'dictionary',\n domain: 'system',\n i18n: true,\n },\n {\n id: 'onboarding',\n name: 'Onboarding Screens',\n kind: 'collection',\n domain: 'app',\n i18n: true,\n fields: {\n title: { type: 'string', required: true },\n description: { type: 'text' },\n image: { type: 'image' },\n order: { type: 'integer', required: true },\n },\n },\n ],\n sample_content: {\n 'app-strings': {\n en: {\n 'welcome': 'Welcome',\n 'loading': 'Loading...',\n 'retry': 'Retry',\n 'ok': 'OK',\n 'cancel': 'Cancel',\n },\n },\n 'error-messages': {\n en: {\n 'network-error': 'No internet connection',\n 'server-error': 'Something went wrong',\n 'auth-error': 'Please sign in again',\n },\n },\n onboarding: {\n en: {\n 'step-1': { title: 'Welcome', description: 'Get started with our app', order: 1 },\n 'step-2': { title: 'Discover', description: 'Explore all features', order: 2 },\n 'step-3': { title: 'Ready', description: 'You are all set!', order: 3 },\n },\n },\n },\n vocabulary: {\n 'get-started': { en: 'Get Started' },\n 'skip': { en: 'Skip' },\n 'next': { en: 'Next' },\n },\n}\n","import type { ScaffoldTemplate } from '@contentrain/types'\nimport { blogTemplate } from './blog.js'\nimport { landingTemplate } from './landing.js'\nimport { docsTemplate } from './docs.js'\nimport { ecommerceTemplate } from './ecommerce.js'\nimport { saasTemplate } from './saas.js'\nimport { i18nTemplate } from './i18n.js'\nimport { mobileTemplate } from './mobile.js'\n\nconst templates: Record<string, ScaffoldTemplate> = {\n blog: blogTemplate,\n landing: landingTemplate,\n docs: docsTemplate,\n ecommerce: ecommerceTemplate,\n saas: saasTemplate,\n i18n: i18nTemplate,\n mobile: mobileTemplate,\n}\n\nexport function getTemplate(id: string): ScaffoldTemplate | null {\n return templates[id] ?? null\n}\n\nexport function listTemplates(): string[] {\n return Object.keys(templates)\n}\n"],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ import { t as readConfig } from "./config-CPlhDwsv.mjs";
2
+ import { t as branchTimestamp } from "./id-BdD4HvMY.mjs";
3
+ import { n as writeContext } from "./context-yh3cuw5N.mjs";
4
+ import { join } from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ import { simpleGit } from "simple-git";
7
+ import { tmpdir } from "node:os";
8
+ //#region src/git/transaction.ts
9
+ async function createTransaction(projectRoot, branchName, options) {
10
+ const git = simpleGit(projectRoot);
11
+ const config = await readConfig(projectRoot);
12
+ const workflow = options?.workflowOverride ?? config?.workflow ?? "auto-merge";
13
+ const remoteName = process.env["CONTENTRAIN_REMOTE"] ?? "origin";
14
+ let baseBranch = process.env["CONTENTRAIN_BRANCH"] ?? config?.repository?.default_branch ?? "";
15
+ if (!baseBranch) try {
16
+ baseBranch = (await git.raw(["branch", "--show-current"])).trim();
17
+ } catch {}
18
+ if (!baseBranch) baseBranch = "main";
19
+ let hasRemote = false;
20
+ try {
21
+ hasRemote = (await git.getRemotes()).some((r) => r.name === remoteName);
22
+ } catch {
23
+ hasRemote = false;
24
+ }
25
+ if (hasRemote) try {
26
+ await git.fetch(remoteName, baseBranch);
27
+ } catch {}
28
+ const worktreePath = join(tmpdir(), `cr-${randomUUID()}`);
29
+ const branch = branchName;
30
+ const baseRef = hasRemote ? `${remoteName}/${baseBranch}` : baseBranch;
31
+ await git.raw([
32
+ "worktree",
33
+ "add",
34
+ worktreePath,
35
+ "-b",
36
+ branch,
37
+ baseRef
38
+ ]);
39
+ const wtGit = simpleGit(worktreePath);
40
+ const authorName = process.env["CONTENTRAIN_AUTHOR_NAME"] ?? "Contentrain";
41
+ const authorEmail = process.env["CONTENTRAIN_AUTHOR_EMAIL"] ?? "mcp@contentrain.io";
42
+ await wtGit.addConfig("user.name", authorName);
43
+ await wtGit.addConfig("user.email", authorEmail);
44
+ let commitHash = "";
45
+ return {
46
+ worktree: worktreePath,
47
+ branch,
48
+ async write(callback) {
49
+ await callback(worktreePath);
50
+ },
51
+ async commit(message) {
52
+ await wtGit.add(".");
53
+ try {
54
+ await wtGit.raw([
55
+ "reset",
56
+ "HEAD",
57
+ "--",
58
+ ".contentrain/context.json"
59
+ ]);
60
+ } catch {}
61
+ commitHash = (await wtGit.commit(message, { "--allow-empty": null })).commit || "";
62
+ return commitHash;
63
+ },
64
+ async complete(contextUpdate) {
65
+ if (workflow === "review") {
66
+ if (hasRemote) await git.push(remoteName, branch);
67
+ return {
68
+ action: "pending-review",
69
+ commit: commitHash
70
+ };
71
+ }
72
+ if (hasRemote) try {
73
+ await git.fetch(remoteName, baseBranch);
74
+ } catch {}
75
+ const status = await git.status();
76
+ if (status.modified.length > 0 || status.not_added.length > 0 || status.created.length > 0) throw new Error("Working tree has uncommitted changes. Commit or stash them before completing the transaction.");
77
+ await git.checkout(baseBranch);
78
+ try {
79
+ await git.merge([branch, "--no-edit"]);
80
+ } catch {
81
+ try {
82
+ await git.merge(["--abort"]);
83
+ } catch {}
84
+ throw new Error(`Merge conflict when merging branch "${branch}" into "${baseBranch}". The branch still exists with your changes intact. Resolve the conflict manually, or delete the branch and retry.`);
85
+ }
86
+ if (hasRemote) try {
87
+ await git.push(remoteName, baseBranch);
88
+ } catch {}
89
+ if (contextUpdate) try {
90
+ await writeContext(projectRoot, contextUpdate);
91
+ await git.add(".contentrain/context.json");
92
+ await git.commit("[contentrain] update context", {
93
+ "--allow-empty": null,
94
+ "--author": `${authorName} <${authorEmail}>`
95
+ });
96
+ } catch {}
97
+ return {
98
+ action: "auto-merged",
99
+ commit: commitHash
100
+ };
101
+ },
102
+ async cleanup() {
103
+ try {
104
+ await git.raw([
105
+ "worktree",
106
+ "remove",
107
+ worktreePath,
108
+ "--force"
109
+ ]);
110
+ } catch {}
111
+ }
112
+ };
113
+ }
114
+ function buildBranchName(scope, target, locale) {
115
+ const ts = branchTimestamp();
116
+ const parts = [
117
+ "contentrain",
118
+ scope,
119
+ target
120
+ ];
121
+ if (locale) parts.push(locale);
122
+ parts.push(ts);
123
+ return parts.join("/");
124
+ }
125
+ //#endregion
126
+ export { createTransaction as n, buildBranchName as t };
127
+
128
+ //# sourceMappingURL=transaction-BsECnmL5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-BsECnmL5.mjs","names":[],"sources":["../src/git/transaction.ts"],"sourcesContent":["import { simpleGit } from 'simple-git'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport { randomUUID } from 'node:crypto'\nimport { readConfig } from '../core/config.js'\nimport { writeContext } from '../core/context.js'\nimport { branchTimestamp } from '../util/id.js'\n\nexport interface ContextUpdate {\n tool: string\n model: string\n locale?: string\n entries?: string[]\n}\n\nexport interface GitTransaction {\n worktree: string\n branch: string\n write(callback: (worktreePath: string) => Promise<void>): Promise<void>\n commit(message: string): Promise<string>\n complete(contextUpdate?: ContextUpdate): Promise<{ action: 'auto-merged' | 'pending-review'; commit: string }>\n cleanup(): Promise<void>\n}\n\nexport async function createTransaction(\n projectRoot: string,\n branchName: string,\n options?: { workflowOverride?: 'review' | 'auto-merge' },\n): Promise<GitTransaction> {\n const git = simpleGit(projectRoot)\n const config = await readConfig(projectRoot)\n const workflow = options?.workflowOverride ?? config?.workflow ?? 'auto-merge'\n\n const remoteName = process.env['CONTENTRAIN_REMOTE'] ?? 'origin'\n\n // Smart base branch detection: env → config → current branch → 'main'\n let baseBranch = process.env['CONTENTRAIN_BRANCH'] ?? config?.repository?.default_branch ?? ''\n if (!baseBranch) {\n try {\n baseBranch = (await git.raw(['branch', '--show-current'])).trim()\n } catch {\n // fallback below\n }\n }\n if (!baseBranch) {\n baseBranch = 'main'\n }\n\n // Detect remote\n let hasRemote = false\n try {\n const remotes = await git.getRemotes()\n hasRemote = remotes.some(r => r.name === remoteName)\n } catch {\n hasRemote = false\n }\n\n // Fetch latest if remote exists\n if (hasRemote) {\n try {\n await git.fetch(remoteName, baseBranch)\n } catch {\n // fetch may fail (no network), continue with local state\n }\n }\n\n const worktreePath = join(tmpdir(), `cr-${randomUUID()}`)\n const branch = branchName\n\n // Create worktree with new branch from base\n const baseRef = hasRemote ? `${remoteName}/${baseBranch}` : baseBranch\n await git.raw(['worktree', 'add', worktreePath, '-b', branch, baseRef])\n\n const wtGit = simpleGit(worktreePath)\n\n // Configure author\n const authorName = process.env['CONTENTRAIN_AUTHOR_NAME'] ?? 'Contentrain'\n const authorEmail = process.env['CONTENTRAIN_AUTHOR_EMAIL'] ?? 'mcp@contentrain.io'\n await wtGit.addConfig('user.name', authorName)\n await wtGit.addConfig('user.email', authorEmail)\n\n let commitHash = ''\n\n return {\n worktree: worktreePath,\n branch,\n\n async write(callback) {\n await callback(worktreePath)\n },\n\n async commit(message) {\n await wtGit.add('.')\n // Exclude context.json from branch commits — it contains timestamps\n // that cause merge conflicts on sequential operations. Context is\n // updated separately on the base branch after merge.\n try {\n await wtGit.raw(['reset', 'HEAD', '--', '.contentrain/context.json'])\n } catch {\n // context.json may not be staged — that's fine\n }\n const result = await wtGit.commit(message, { '--allow-empty': null })\n commitHash = result.commit || ''\n return commitHash\n },\n\n async complete(contextUpdate?: ContextUpdate) {\n if (workflow === 'review') {\n if (hasRemote) {\n await git.push(remoteName, branch)\n }\n return { action: 'pending-review', commit: commitHash }\n }\n\n // auto-merge: merge branch into base\n if (hasRemote) {\n try {\n await git.fetch(remoteName, baseBranch)\n } catch {\n // continue with local state\n }\n }\n\n // Ensure working tree is clean before checkout\n const status = await git.status()\n if (status.modified.length > 0 || status.not_added.length > 0 || status.created.length > 0) {\n throw new Error('Working tree has uncommitted changes. Commit or stash them before completing the transaction.')\n }\n\n await git.checkout(baseBranch)\n\n try {\n await git.merge([branch, '--no-edit'])\n } catch {\n // Merge conflict — abort and let the user resolve manually.\n try {\n await git.merge(['--abort'])\n } catch {\n // abort may fail if not in merge state\n }\n throw new Error(\n `Merge conflict when merging branch \"${branch}\" into \"${baseBranch}\". `\n + `The branch still exists with your changes intact. `\n + `Resolve the conflict manually, or delete the branch and retry.`,\n )\n }\n\n if (hasRemote) {\n try {\n await git.push(remoteName, baseBranch)\n } catch {\n // push may fail, branch is merged locally\n }\n }\n\n // Update context.json on base branch after successful merge\n if (contextUpdate) {\n try {\n await writeContext(projectRoot, contextUpdate)\n await git.add('.contentrain/context.json')\n await git.commit('[contentrain] update context', { '--allow-empty': null, '--author': `${authorName} <${authorEmail}>` })\n } catch {\n // Context update is best-effort — don't fail the transaction\n }\n }\n\n return { action: 'auto-merged', commit: commitHash }\n },\n\n async cleanup() {\n try {\n await git.raw(['worktree', 'remove', worktreePath, '--force'])\n } catch {\n // worktree may already be cleaned up\n }\n },\n }\n}\n\nexport function buildBranchName(scope: string, target: string, locale?: string): string {\n const ts = branchTimestamp()\n const parts = ['contentrain', scope, target]\n if (locale) parts.push(locale)\n parts.push(ts)\n return parts.join('/')\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { t as parseTsx } from "./tsx-parser-CYVyBWjn.mjs";
2
+ export { parseTsx };
@@ -0,0 +1,234 @@
1
+ import ts from "typescript";
2
+ //#region src/core/ast-scanner/tsx-parser.ts
3
+ const SURROUNDING_MAX = 120;
4
+ /**
5
+ * Parse a TSX/JSX/TS/JS file and extract all string literals with structural context.
6
+ *
7
+ * Uses TypeScript's syntax-only parser (no type checking, no tsconfig needed).
8
+ * Walks the AST and classifies each string by its parent chain.
9
+ */
10
+ function parseTsx(content, fileName) {
11
+ const scriptKind = getScriptKind(fileName);
12
+ const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, scriptKind);
13
+ const results = [];
14
+ visit(sourceFile, sourceFile, content.split("\n"), results);
15
+ return results;
16
+ }
17
+ function getScriptKind(fileName) {
18
+ const lower = fileName.toLowerCase();
19
+ if (lower.endsWith(".tsx")) return ts.ScriptKind.TSX;
20
+ if (lower.endsWith(".jsx")) return ts.ScriptKind.JSX;
21
+ if (lower.endsWith(".ts")) return ts.ScriptKind.TS;
22
+ return ts.ScriptKind.JS;
23
+ }
24
+ function visit(node, sourceFile, lines, results) {
25
+ if (ts.isJsxText(node)) {
26
+ const text = node.text.trim();
27
+ if (text.length > 0) {
28
+ const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
29
+ const parent = getJsxParentTag(node);
30
+ results.push({
31
+ value: text,
32
+ line: lineIdx + 1,
33
+ column: character + 1,
34
+ context: "jsx_text",
35
+ scope: "script",
36
+ parent,
37
+ surrounding: buildSurrounding(lines, lineIdx)
38
+ });
39
+ }
40
+ return;
41
+ }
42
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
43
+ const value = node.text;
44
+ if (value.length === 0) return;
45
+ const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
46
+ const classification = classifyByParentChain(node, sourceFile);
47
+ results.push({
48
+ value,
49
+ line: lineIdx + 1,
50
+ column: character + 1,
51
+ context: classification.context,
52
+ scope: "script",
53
+ parent: classification.parent,
54
+ parentProperty: classification.parentProperty,
55
+ surrounding: buildSurrounding(lines, lineIdx)
56
+ });
57
+ return;
58
+ }
59
+ if (ts.isTemplateExpression(node)) {
60
+ extractTemplateParts(node, sourceFile, lines, results);
61
+ return;
62
+ }
63
+ ts.forEachChild(node, (child) => {
64
+ visit(child, sourceFile, lines, results);
65
+ });
66
+ }
67
+ function extractTemplateParts(node, sourceFile, lines, results) {
68
+ const classification = classifyByParentChain(node, sourceFile);
69
+ const headText = node.head.text;
70
+ if (headText.length > 0) {
71
+ const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.head.getStart(sourceFile));
72
+ results.push({
73
+ value: headText,
74
+ line: lineIdx + 1,
75
+ column: character + 1,
76
+ context: classification.context,
77
+ scope: "script",
78
+ parent: classification.parent,
79
+ parentProperty: classification.parentProperty,
80
+ surrounding: buildSurrounding(lines, lineIdx)
81
+ });
82
+ }
83
+ for (const span of node.templateSpans) {
84
+ const spanText = span.literal.text;
85
+ if (spanText.length > 0) {
86
+ const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(span.literal.getStart(sourceFile));
87
+ results.push({
88
+ value: spanText,
89
+ line: lineIdx + 1,
90
+ column: character + 1,
91
+ context: classification.context,
92
+ scope: "script",
93
+ parent: classification.parent,
94
+ parentProperty: classification.parentProperty,
95
+ surrounding: buildSurrounding(lines, lineIdx)
96
+ });
97
+ }
98
+ visit(span.expression, sourceFile, lines, results);
99
+ }
100
+ }
101
+ function classifyByParentChain(node, sourceFile) {
102
+ let current = node.parent;
103
+ while (current) {
104
+ if (ts.isImportDeclaration(current) || ts.isExportDeclaration(current)) return {
105
+ context: "import_path",
106
+ parent: "import"
107
+ };
108
+ if (ts.isCallExpression(current) && current.expression.kind === ts.SyntaxKind.ImportKeyword) return {
109
+ context: "import_path",
110
+ parent: "import"
111
+ };
112
+ if (ts.isCallExpression(current) && ts.isIdentifier(current.expression) && current.expression.text === "require") return {
113
+ context: "import_path",
114
+ parent: "require"
115
+ };
116
+ if (ts.isJsxAttribute(current)) {
117
+ const attrName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile);
118
+ if (attrName === "className" || attrName === "class" || attrName === "style") return {
119
+ context: "css_class",
120
+ parent: attrName
121
+ };
122
+ return {
123
+ context: "jsx_attribute",
124
+ parent: attrName
125
+ };
126
+ }
127
+ if (ts.isVariableDeclaration(current)) return {
128
+ context: "variable_assignment",
129
+ parent: ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)
130
+ };
131
+ if (ts.isPropertyAssignment(current)) {
132
+ const key = ts.isIdentifier(current.name) ? current.name.text : ts.isStringLiteral(current.name) ? current.name.text : current.name.getText(sourceFile);
133
+ return {
134
+ context: "object_property",
135
+ parent: key,
136
+ parentProperty: key
137
+ };
138
+ }
139
+ if (ts.isEnumMember(current)) return {
140
+ context: "enum_value",
141
+ parent: ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)
142
+ };
143
+ if (ts.isCallExpression(current)) {
144
+ const callee = getCalleeName(current.expression, sourceFile);
145
+ if ([
146
+ "cn",
147
+ "clsx",
148
+ "classNames",
149
+ "twMerge",
150
+ "twJoin",
151
+ "cva",
152
+ "cx"
153
+ ].includes(callee)) return {
154
+ context: "css_utility_call",
155
+ parent: callee
156
+ };
157
+ if (callee.startsWith("console.")) return {
158
+ context: "console_call",
159
+ parent: callee
160
+ };
161
+ if ([
162
+ "describe",
163
+ "it",
164
+ "test",
165
+ "expect",
166
+ "beforeEach",
167
+ "afterEach",
168
+ "beforeAll",
169
+ "afterAll"
170
+ ].includes(callee)) return {
171
+ context: "test_assertion",
172
+ parent: callee
173
+ };
174
+ return {
175
+ context: "function_argument",
176
+ parent: callee
177
+ };
178
+ }
179
+ if (ts.isArrayLiteralExpression(current)) return {
180
+ context: "array_element",
181
+ parent: "array"
182
+ };
183
+ if (ts.isCaseClause(current)) return {
184
+ context: "switch_case",
185
+ parent: "case"
186
+ };
187
+ if (ts.isTypeAliasDeclaration(current) || ts.isTypeReferenceNode(current) || ts.isInterfaceDeclaration(current) || ts.isTypeLiteralNode(current) || ts.isLiteralTypeNode(current) || ts.isUnionTypeNode(current) || ts.isIntersectionTypeNode(current)) return {
188
+ context: "type_annotation",
189
+ parent: "type"
190
+ };
191
+ if (ts.isPropertySignature(current)) return {
192
+ context: "type_annotation",
193
+ parent: "type"
194
+ };
195
+ current = current.parent;
196
+ }
197
+ return {
198
+ context: "other",
199
+ parent: ""
200
+ };
201
+ }
202
+ function getCalleeName(expr, sourceFile) {
203
+ if (ts.isIdentifier(expr)) return expr.text;
204
+ if (ts.isPropertyAccessExpression(expr)) {
205
+ const obj = getCalleeName(expr.expression, sourceFile);
206
+ return obj ? `${obj}.${expr.name.text}` : expr.name.text;
207
+ }
208
+ return expr.getText(sourceFile);
209
+ }
210
+ function getJsxParentTag(node) {
211
+ let current = node.parent;
212
+ while (current) {
213
+ if (ts.isJsxElement(current)) return current.openingElement.tagName.getText();
214
+ if (ts.isJsxFragment(current)) return "Fragment";
215
+ current = current.parent;
216
+ }
217
+ return "";
218
+ }
219
+ function buildSurrounding(lines, lineIdx) {
220
+ const start = Math.max(0, lineIdx - 1);
221
+ const end = Math.min(lines.length - 1, lineIdx + 1);
222
+ const parts = [];
223
+ for (let i = start; i <= end; i++) {
224
+ const line = lines[i];
225
+ if (line !== void 0) parts.push(line);
226
+ }
227
+ const joined = parts.join("\n");
228
+ if (joined.length > SURROUNDING_MAX) return joined.slice(0, SURROUNDING_MAX);
229
+ return joined;
230
+ }
231
+ //#endregion
232
+ export { parseTsx as t };
233
+
234
+ //# sourceMappingURL=tsx-parser-CYVyBWjn.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsx-parser-CYVyBWjn.mjs","names":[],"sources":["../src/core/ast-scanner/tsx-parser.ts"],"sourcesContent":["import ts from 'typescript'\nimport type { ExtractedString, StructuralContext } from './types.js'\n\n// ─── Constants ───\n\nconst SURROUNDING_MAX = 120\n\n// ─── Public API ───\n\n/**\n * Parse a TSX/JSX/TS/JS file and extract all string literals with structural context.\n *\n * Uses TypeScript's syntax-only parser (no type checking, no tsconfig needed).\n * Walks the AST and classifies each string by its parent chain.\n */\nexport function parseTsx(content: string, fileName: string): ExtractedString[] {\n const scriptKind = getScriptKind(fileName)\n const sourceFile = ts.createSourceFile(\n fileName,\n content,\n ts.ScriptTarget.Latest,\n /* setParentNodes */ true,\n scriptKind,\n )\n\n const results: ExtractedString[] = []\n const lines = content.split('\\n')\n\n visit(sourceFile, sourceFile, lines, results)\n\n return results\n}\n\n// ─── Script kind detection ───\n\nfunction getScriptKind(fileName: string): ts.ScriptKind {\n const lower = fileName.toLowerCase()\n if (lower.endsWith('.tsx')) return ts.ScriptKind.TSX\n if (lower.endsWith('.jsx')) return ts.ScriptKind.JSX\n if (lower.endsWith('.ts')) return ts.ScriptKind.TS\n return ts.ScriptKind.JS\n}\n\n// ─── AST Walker ───\n\nfunction visit(\n node: ts.Node,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n // Handle JsxText nodes\n if (ts.isJsxText(node)) {\n const text = node.text.trim()\n // Skip whitespace-only or empty JsxText\n if (text.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const parent = getJsxParentTag(node)\n results.push({\n value: text,\n line: lineIdx + 1,\n column: character + 1,\n context: 'jsx_text',\n scope: 'script',\n parent,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n return\n }\n\n // Handle string literals\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n const value = node.text\n // Skip empty strings\n if (value.length === 0) return\n\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))\n const classification = classifyByParentChain(node, sourceFile)\n\n results.push({\n value,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n return\n }\n\n // Handle template literals with expressions — extract static head/spans\n if (ts.isTemplateExpression(node)) {\n extractTemplateParts(node, sourceFile, lines, results)\n return\n }\n\n ts.forEachChild(node, (child) => {\n visit(child, sourceFile, lines, results)\n })\n}\n\n// ─── Template literal parts extraction ───\n\nfunction extractTemplateParts(\n node: ts.TemplateExpression,\n sourceFile: ts.SourceFile,\n lines: string[],\n results: ExtractedString[],\n): void {\n const classification = classifyByParentChain(node, sourceFile)\n\n // Head: text before first ${...}\n const headText = node.head.text\n if (headText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(node.head.getStart(sourceFile))\n results.push({\n value: headText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Template spans: text after each ${...} expression\n for (const span of node.templateSpans) {\n const spanText = span.literal.text\n if (spanText.length > 0) {\n const { line: lineIdx, character } = sourceFile.getLineAndCharacterOfPosition(span.literal.getStart(sourceFile))\n results.push({\n value: spanText,\n line: lineIdx + 1,\n column: character + 1,\n context: classification.context,\n scope: 'script',\n parent: classification.parent,\n parentProperty: classification.parentProperty,\n surrounding: buildSurrounding(lines, lineIdx),\n })\n }\n\n // Visit the expression inside ${...} for nested strings\n visit(span.expression, sourceFile, lines, results)\n }\n}\n\n// ─── Parent chain classification ───\n\ninterface Classification {\n context: StructuralContext\n parent: string\n parentProperty?: string\n}\n\nfunction classifyByParentChain(node: ts.Node, sourceFile: ts.SourceFile): Classification {\n let current = node.parent\n\n while (current) {\n // Import / Export declaration → import_path\n if (ts.isImportDeclaration(current) || ts.isExportDeclaration(current)) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // Import specifier module path (dynamic import)\n if (ts.isCallExpression(current) && current.expression.kind === ts.SyntaxKind.ImportKeyword) {\n return { context: 'import_path', parent: 'import' }\n }\n\n // require() calls\n if (\n ts.isCallExpression(current)\n && ts.isIdentifier(current.expression)\n && current.expression.text === 'require'\n ) {\n return { context: 'import_path', parent: 'require' }\n }\n\n // JSX attribute → jsx_attribute or css_class\n if (ts.isJsxAttribute(current)) {\n const attrName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n // className / class / style → CSS, not content\n if (attrName === 'className' || attrName === 'class' || attrName === 'style') {\n return { context: 'css_class', parent: attrName }\n }\n return { context: 'jsx_attribute', parent: attrName }\n }\n\n // Variable declaration → variable_assignment\n if (ts.isVariableDeclaration(current)) {\n const varName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'variable_assignment', parent: varName }\n }\n\n // Property assignment → object_property\n if (ts.isPropertyAssignment(current)) {\n const key = ts.isIdentifier(current.name)\n ? current.name.text\n : ts.isStringLiteral(current.name)\n ? current.name.text\n : current.name.getText(sourceFile)\n return { context: 'object_property', parent: key, parentProperty: key }\n }\n\n // Enum member → enum_value\n if (ts.isEnumMember(current)) {\n const enumName = ts.isIdentifier(current.name) ? current.name.text : current.name.getText(sourceFile)\n return { context: 'enum_value', parent: enumName }\n }\n\n // Call expression → function_argument or css_utility_call or console_call or test_assertion\n if (ts.isCallExpression(current)) {\n const callee = getCalleeName(current.expression, sourceFile)\n // CSS utility functions\n if (['cn', 'clsx', 'classNames', 'twMerge', 'twJoin', 'cva', 'cx'].includes(callee)) {\n return { context: 'css_utility_call', parent: callee }\n }\n // Console calls\n if (callee.startsWith('console.')) {\n return { context: 'console_call', parent: callee }\n }\n // Test assertions\n if (['describe', 'it', 'test', 'expect', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll'].includes(callee)) {\n return { context: 'test_assertion', parent: callee }\n }\n return { context: 'function_argument', parent: callee }\n }\n\n // Array literal → array_element\n if (ts.isArrayLiteralExpression(current)) {\n return { context: 'array_element', parent: 'array' }\n }\n\n // Case clause → switch_case\n if (ts.isCaseClause(current)) {\n return { context: 'switch_case', parent: 'case' }\n }\n\n // Type contexts → type_annotation\n if (\n ts.isTypeAliasDeclaration(current)\n || ts.isTypeReferenceNode(current)\n || ts.isInterfaceDeclaration(current)\n || ts.isTypeLiteralNode(current)\n || ts.isLiteralTypeNode(current)\n || ts.isUnionTypeNode(current)\n || ts.isIntersectionTypeNode(current)\n ) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n // Property declaration with type context (e.g., `as const` typed properties)\n // Check if we're inside a type annotation specifically\n if (ts.isPropertySignature(current)) {\n return { context: 'type_annotation', parent: 'type' }\n }\n\n current = current.parent\n }\n\n return { context: 'other', parent: '' }\n}\n\n// ─── Callee name extraction ───\n\nfunction getCalleeName(expr: ts.Expression, sourceFile: ts.SourceFile): string {\n if (ts.isIdentifier(expr)) {\n return expr.text\n }\n if (ts.isPropertyAccessExpression(expr)) {\n // e.g., console.log → \"console.log\"\n const obj = getCalleeName(expr.expression, sourceFile)\n return obj ? `${obj}.${expr.name.text}` : expr.name.text\n }\n return expr.getText(sourceFile)\n}\n\n// ─── JSX parent tag extraction ───\n\nfunction getJsxParentTag(node: ts.Node): string {\n let current = node.parent\n\n while (current) {\n if (ts.isJsxElement(current)) {\n const tagName = current.openingElement.tagName.getText()\n return tagName\n }\n if (ts.isJsxFragment(current)) {\n return 'Fragment'\n }\n current = current.parent\n }\n\n return ''\n}\n\n// ─── Surrounding code builder ───\n\nfunction buildSurrounding(lines: string[], lineIdx: number): string {\n const start = Math.max(0, lineIdx - 1)\n const end = Math.min(lines.length - 1, lineIdx + 1)\n\n const parts: string[] = []\n for (let i = start; i <= end; i++) {\n const line = lines[i]\n if (line !== undefined) {\n parts.push(line)\n }\n }\n\n const joined = parts.join('\\n')\n if (joined.length > SURROUNDING_MAX) {\n return joined.slice(0, SURROUNDING_MAX)\n }\n return joined\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { Platform, StackType } from "@contentrain/types";
2
+
3
+ //#region src/util/detect.d.ts
4
+ interface StackInfo {
5
+ stack: StackType;
6
+ platform: Platform;
7
+ name: string;
8
+ description: string;
9
+ monorepo: boolean;
10
+ monorepoTool?: string;
11
+ features: string[];
12
+ }
13
+ declare function inferPlatform(stack: StackType): Platform;
14
+ /** Backward-compatible: returns just the StackType string */
15
+ declare function detectStack(projectRoot: string): Promise<StackType>;
16
+ /** Rich detection: stack + platform + monorepo + features */
17
+ declare function detectStackInfo(projectRoot: string): Promise<StackInfo>;
18
+ //#endregion
19
+ export { StackInfo, detectStack, detectStackInfo, inferPlatform };
20
+ //# sourceMappingURL=detect.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.mts","names":[],"sources":["../../src/util/detect.ts"],"mappings":";;;UAUiB,SAAA;EACf,KAAA,EAAO,SAAA;EACP,QAAA,EAAU,QAAA;EACV,IAAA;EACA,WAAA;EACA,QAAA;EACA,YAAA;EACA,QAAA;AAAA;AAAA,iBA2Cc,aAAA,CAAc,KAAA,EAAO,SAAA,GAAY,QAAA;;iBAoB3B,WAAA,CAAY,WAAA,WAAsB,OAAA,CAAQ,SAAA;;iBAM1C,eAAA,CAAgB,WAAA,WAAsB,OAAA,CAAQ,SAAA"}
@@ -0,0 +1,2 @@
1
+ import { n as detectStackInfo, r as inferPlatform, t as detectStack } from "../detect-C8XmJ4S6.mjs";
2
+ export { detectStack, detectStackInfo, inferPlatform };
@@ -0,0 +1,12 @@
1
+ //#region src/util/fs.d.ts
2
+ declare function pathExists(filePath: string): Promise<boolean>;
3
+ declare function readJson<T>(filePath: string): Promise<T | null>;
4
+ declare function readDir(dirPath: string): Promise<string[]>;
5
+ declare function writeJson(filePath: string, data: unknown, fieldOrder?: string[]): Promise<void>;
6
+ declare function ensureDir(dirPath: string): Promise<void>;
7
+ declare function readText(filePath: string): Promise<string | null>;
8
+ declare function writeText(filePath: string, content: string): Promise<void>;
9
+ declare function contentrainDir(projectRoot: string): string;
10
+ //#endregion
11
+ export { contentrainDir, ensureDir, pathExists, readDir, readJson, readText, writeJson, writeText };
12
+ //# sourceMappingURL=fs.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.mts","names":[],"sources":["../../src/util/fs.ts"],"mappings":";iBAIsB,UAAA,CAAW,QAAA,WAAmB,OAAA;AAAA,iBAS9B,QAAA,GAAA,CAAY,QAAA,WAAmB,OAAA,CAAQ,CAAA;AAAA,iBASvC,OAAA,CAAQ,OAAA,WAAkB,OAAA;AAAA,iBAQ1B,SAAA,CAAU,QAAA,UAAkB,IAAA,WAAe,UAAA,cAAwB,OAAA;AAAA,iBAKnE,SAAA,CAAU,OAAA,WAAkB,OAAA;AAAA,iBAI5B,QAAA,CAAS,QAAA,WAAmB,OAAA;AAAA,iBAQ5B,SAAA,CAAU,QAAA,UAAkB,OAAA,WAAkB,OAAA;AAAA,iBAKpD,cAAA,CAAe,WAAA"}
@@ -0,0 +1,2 @@
1
+ import { a as readJson, c as writeText, i as readDir, n as ensureDir, o as readText, r as pathExists, s as writeJson, t as contentrainDir } from "../fs-BbuGnVcG.mjs";
2
+ export { contentrainDir, ensureDir, pathExists, readDir, readJson, readText, writeJson, writeText };
@@ -0,0 +1,6 @@
1
+ //#region src/util/id.d.ts
2
+ declare function branchTimestamp(): string;
3
+ declare function generateEntryId(): string;
4
+ //#endregion
5
+ export { branchTimestamp, generateEntryId };
6
+ //# sourceMappingURL=id.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.d.mts","names":[],"sources":["../../src/util/id.ts"],"mappings":";iBAEgB,eAAA,CAAA;AAAA,iBAMA,eAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ import { n as generateEntryId, t as branchTimestamp } from "../id-BdD4HvMY.mjs";
2
+ export { branchTimestamp, generateEntryId };
@@ -0,0 +1,14 @@
1
+ //#region src/util/serializer.d.ts
2
+ /**
3
+ * Canonical JSON serialization — deterministic output for git diff stability.
4
+ *
5
+ * Rules (spec Section 14.10):
6
+ * - Top-level keys: lexicographic sort
7
+ * - Entry fields: follow fieldOrder if provided, else lexicographic
8
+ * - 2-space indent, UTF-8, trailing newline
9
+ * - Null/undefined values omitted
10
+ */
11
+ declare function canonicalStringify(data: unknown, fieldOrder?: string[]): string;
12
+ //#endregion
13
+ export { canonicalStringify };
14
+ //# sourceMappingURL=serializer.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.d.mts","names":[],"sources":["../../src/util/serializer.ts"],"mappings":";;AAgCA;;;;;;;;iBAAgB,kBAAA,CAAmB,IAAA,WAAe,UAAA"}
@@ -0,0 +1,2 @@
1
+ import { t as canonicalStringify } from "../serializer-Dueih-i2.mjs";
2
+ export { canonicalStringify };