@contentrain/mcp 1.2.1 → 1.4.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 (183) hide show
  1. package/README.md +93 -25
  2. package/dist/annotations-Clhbw2lh.mjs +126 -0
  3. package/dist/annotations-Clhbw2lh.mjs.map +1 -0
  4. package/dist/{apply-manager-BkPMfpsN.mjs → apply-manager-D5ym5Jba.mjs} +7 -7
  5. package/dist/{apply-manager-BkPMfpsN.mjs.map → apply-manager-D5ym5Jba.mjs.map} +1 -1
  6. package/dist/{astro-parser-BJ-54JGe.mjs → astro-parser-B-nLl0zE.mjs} +3 -3
  7. package/dist/{astro-parser-BJ-54JGe.mjs.map → astro-parser-B-nLl0zE.mjs.map} +1 -1
  8. package/dist/{branch-lifecycle-wGJg25LT.mjs → branch-lifecycle-CFVpTpNT.mjs} +33 -3
  9. package/dist/{branch-lifecycle-wGJg25LT.mjs.map → branch-lifecycle-CFVpTpNT.mjs.map} +1 -1
  10. package/dist/{compiler-rIC4ETHv.mjs → compiler-k4yttlzM.mjs} +2 -2
  11. package/dist/{compiler-rIC4ETHv.mjs.map → compiler-k4yttlzM.mjs.map} +1 -1
  12. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs → compiler-sfc.cjs-D0d_OicF.mjs} +2 -2
  13. package/dist/{compiler-sfc.cjs-BbD04rn_.mjs.map → compiler-sfc.cjs-D0d_OicF.mjs.map} +1 -1
  14. package/dist/config-BIl5Ybj0.mjs +40 -0
  15. package/dist/config-BIl5Ybj0.mjs.map +1 -0
  16. package/dist/content-manager-DqDLSNQ-.d.mts +63 -0
  17. package/dist/content-manager-DqDLSNQ-.d.mts.map +1 -0
  18. package/dist/context-J0OU9Nfp.mjs +102 -0
  19. package/dist/context-J0OU9Nfp.mjs.map +1 -0
  20. package/dist/contracts-DfL0BfrD.mjs +2 -0
  21. package/dist/core/apply-manager.mjs +10 -10
  22. package/dist/core/config.d.mts +13 -0
  23. package/dist/core/config.d.mts.map +1 -1
  24. package/dist/core/config.mjs +2 -3
  25. package/dist/core/content-manager.d.mts +2 -45
  26. package/dist/core/content-manager.mjs +3 -4
  27. package/dist/core/context.d.mts +32 -2
  28. package/dist/core/context.d.mts.map +1 -1
  29. package/dist/core/context.mjs +7 -7
  30. package/dist/core/contracts/index.d.mts +2 -0
  31. package/dist/core/contracts/index.mjs +2 -0
  32. package/dist/core/doctor.d.mts +76 -0
  33. package/dist/core/doctor.d.mts.map +1 -0
  34. package/dist/core/doctor.mjs +8 -0
  35. package/dist/core/graph-builder.mjs +3 -4
  36. package/dist/core/meta-manager.mjs +2 -3
  37. package/dist/core/model-manager.d.mts +34 -1
  38. package/dist/core/model-manager.d.mts.map +1 -1
  39. package/dist/core/model-manager.mjs +3 -4
  40. package/dist/core/ops/index.d.mts +137 -0
  41. package/dist/core/ops/index.d.mts.map +1 -0
  42. package/dist/core/ops/index.mjs +4 -0
  43. package/dist/core/overlay-reader.d.mts +42 -0
  44. package/dist/core/overlay-reader.d.mts.map +1 -0
  45. package/dist/core/overlay-reader.mjs +2 -0
  46. package/dist/core/scan-config.mjs +2 -3
  47. package/dist/core/scanner.mjs +4 -5
  48. package/dist/core/validator/index.d.mts +129 -0
  49. package/dist/core/validator/index.d.mts.map +1 -0
  50. package/dist/core/validator/index.mjs +6 -0
  51. package/dist/{detect-DinOQAmK.mjs → detect-DL9mFmaS.mjs} +2 -2
  52. package/dist/{detect-DinOQAmK.mjs.map → detect-DL9mFmaS.mjs.map} +1 -1
  53. package/dist/doctor-CgBoT6h1.mjs +338 -0
  54. package/dist/doctor-CgBoT6h1.mjs.map +1 -0
  55. package/dist/{fs-BnIQ4dKj.mjs → fs-DLbVB-Ek.mjs} +2 -2
  56. package/dist/fs-DLbVB-Ek.mjs.map +1 -0
  57. package/dist/git/branch-lifecycle.d.mts +30 -1
  58. package/dist/git/branch-lifecycle.d.mts.map +1 -1
  59. package/dist/git/branch-lifecycle.mjs +4 -5
  60. package/dist/git/transaction.d.mts +2 -2
  61. package/dist/git/transaction.d.mts.map +1 -1
  62. package/dist/git/transaction.mjs +8 -8
  63. package/dist/{graph-builder-tM7zj-SX.mjs → graph-builder-DXv2JEp-.mjs} +3 -3
  64. package/dist/{graph-builder-tM7zj-SX.mjs.map → graph-builder-DXv2JEp-.mjs.map} +1 -1
  65. package/dist/{id-DV_T9Ic8.mjs → id-CIO9s0x_.mjs} +1 -1
  66. package/dist/{id-DV_T9Ic8.mjs.map → id-CIO9s0x_.mjs.map} +1 -1
  67. package/dist/index-D0wQJSgs.d.mts +2 -0
  68. package/dist/index.mjs +22 -17
  69. package/dist/index.mjs.map +1 -1
  70. package/dist/local-DvP4Y4T-.mjs +182 -0
  71. package/dist/local-DvP4Y4T-.mjs.map +1 -0
  72. package/dist/{meta-manager--0IwAPCl.mjs → meta-manager-C900rEyG.mjs} +2 -2
  73. package/dist/{meta-manager--0IwAPCl.mjs.map → meta-manager-C900rEyG.mjs.map} +1 -1
  74. package/dist/{model-manager-DW_fOGRM.mjs → model-manager-BhLsUgaB.mjs} +241 -49
  75. package/dist/model-manager-BhLsUgaB.mjs.map +1 -0
  76. package/dist/{node-Cbq5eR5i.mjs → node-DN9hZeil.mjs} +1 -1
  77. package/dist/{node-Cbq5eR5i.mjs.map → node-DN9hZeil.mjs.map} +1 -1
  78. package/dist/ops-DjEWi5Wa.mjs +486 -0
  79. package/dist/ops-DjEWi5Wa.mjs.map +1 -0
  80. package/dist/overlay-reader-DOdyDRIv.mjs +74 -0
  81. package/dist/overlay-reader-DOdyDRIv.mjs.map +1 -0
  82. package/dist/paths-C3xNyc7z.mjs +52 -0
  83. package/dist/paths-C3xNyc7z.mjs.map +1 -0
  84. package/dist/paths-CYl5vCBD.mjs +54 -0
  85. package/dist/paths-CYl5vCBD.mjs.map +1 -0
  86. package/dist/providers/github/index.d.mts +201 -0
  87. package/dist/providers/github/index.d.mts.map +1 -0
  88. package/dist/providers/github/index.mjs +494 -0
  89. package/dist/providers/github/index.mjs.map +1 -0
  90. package/dist/providers/gitlab/index.d.mts +158 -0
  91. package/dist/providers/gitlab/index.d.mts.map +1 -0
  92. package/dist/providers/gitlab/index.mjs +361 -0
  93. package/dist/providers/gitlab/index.mjs.map +1 -0
  94. package/dist/providers/local/index.d.mts +106 -0
  95. package/dist/providers/local/index.d.mts.map +1 -0
  96. package/dist/providers/local/index.mjs +12 -0
  97. package/dist/{scan-config-QgnJ1-52.mjs → scan-config-jC6XmiqF.mjs} +2 -2
  98. package/dist/{scan-config-QgnJ1-52.mjs.map → scan-config-jC6XmiqF.mjs.map} +1 -1
  99. package/dist/{scanner-DUoXnmtI.mjs → scanner-DKMwc03k.mjs} +7 -7
  100. package/dist/{scanner-DUoXnmtI.mjs.map → scanner-DKMwc03k.mjs.map} +1 -1
  101. package/dist/serialization-B1CEzR4H.mjs +2 -0
  102. package/dist/server/http/index.d.mts +107 -0
  103. package/dist/server/http/index.d.mts.map +1 -0
  104. package/dist/server/http/index.mjs +248 -0
  105. package/dist/server/http/index.mjs.map +1 -0
  106. package/dist/{server-Dtq8vqbK.mjs → server-BkhhtEE2.mjs} +486 -355
  107. package/dist/server-BkhhtEE2.mjs.map +1 -0
  108. package/dist/server-WqGx6ait.d.mts +50 -0
  109. package/dist/server-WqGx6ait.d.mts.map +1 -0
  110. package/dist/server.d.mts +2 -7
  111. package/dist/server.mjs +22 -17
  112. package/dist/{source-map-generator-DpO-ejrt.mjs → source-map-generator-BWDva49I.mjs} +1 -1
  113. package/dist/{source-map-generator-DpO-ejrt.mjs.map → source-map-generator-BWDva49I.mjs.map} +1 -1
  114. package/dist/{svelte-parser-1bBcMx3T.mjs → svelte-parser-Dr9mmZuk.mjs} +3 -3
  115. package/dist/{svelte-parser-1bBcMx3T.mjs.map → svelte-parser-Dr9mmZuk.mjs.map} +1 -1
  116. package/dist/templates/index.mjs +1 -1
  117. package/dist/{templates-bRPzYq4M.mjs → templates-VrLVqfe5.mjs} +1 -1
  118. package/dist/{templates-bRPzYq4M.mjs.map → templates-VrLVqfe5.mjs.map} +1 -1
  119. package/dist/testing/conformance.d.mts +59 -0
  120. package/dist/testing/conformance.d.mts.map +1 -0
  121. package/dist/testing/conformance.mjs +59 -0
  122. package/dist/testing/conformance.mjs.map +1 -0
  123. package/dist/tools/annotations.d.mts +24 -0
  124. package/dist/tools/annotations.d.mts.map +1 -0
  125. package/dist/tools/annotations.mjs +2 -0
  126. package/dist/{transaction-C_Pvux78.mjs → transaction-DgkNgWSI.mjs} +61 -32
  127. package/dist/transaction-DgkNgWSI.mjs.map +1 -0
  128. package/dist/tsx-parser-BOMZE_yQ.mjs +2 -0
  129. package/dist/{tsx-parser-BWiMGAIR.mjs → tsx-parser-CQc6nr-o.mjs} +1 -1
  130. package/dist/{tsx-parser-BWiMGAIR.mjs.map → tsx-parser-CQc6nr-o.mjs.map} +1 -1
  131. package/dist/util/detect.mjs +2 -3
  132. package/dist/util/fs.mjs +1 -2
  133. package/dist/util/id.mjs +1 -1
  134. package/dist/validator-B0nNRFeU.mjs +906 -0
  135. package/dist/validator-B0nNRFeU.mjs.map +1 -0
  136. package/dist/{vue-parser-DTPTN3Yb.mjs → vue-parser-COgjArqv.mjs} +3 -3
  137. package/dist/{vue-parser-DTPTN3Yb.mjs.map → vue-parser-COgjArqv.mjs.map} +1 -1
  138. package/package.json +82 -23
  139. package/testing/conformance/01-new-collection-entry/expected/.contentrain/config.json +15 -0
  140. package/testing/conformance/01-new-collection-entry/expected/.contentrain/content/blog/blog/en.json +6 -0
  141. package/testing/conformance/01-new-collection-entry/expected/.contentrain/context.json +22 -0
  142. package/testing/conformance/01-new-collection-entry/expected/.contentrain/meta/blog/en.json +7 -0
  143. package/testing/conformance/01-new-collection-entry/expected/.contentrain/models/blog.json +16 -0
  144. package/testing/conformance/01-new-collection-entry/scenario.json +19 -0
  145. package/testing/conformance/01-new-collection-entry/setup/.contentrain/config.json +15 -0
  146. package/testing/conformance/01-new-collection-entry/setup/.contentrain/models/blog.json +16 -0
  147. package/testing/conformance/02-new-singleton/expected/.contentrain/config.json +15 -0
  148. package/testing/conformance/02-new-singleton/expected/.contentrain/content/marketing/hero/en.json +4 -0
  149. package/testing/conformance/02-new-singleton/expected/.contentrain/context.json +22 -0
  150. package/testing/conformance/02-new-singleton/expected/.contentrain/meta/hero/en.json +5 -0
  151. package/testing/conformance/02-new-singleton/expected/.contentrain/models/hero.json +16 -0
  152. package/testing/conformance/02-new-singleton/scenario.json +18 -0
  153. package/testing/conformance/02-new-singleton/setup/.contentrain/config.json +15 -0
  154. package/testing/conformance/02-new-singleton/setup/.contentrain/models/hero.json +16 -0
  155. package/testing/conformance/03-new-dictionary/expected/.contentrain/config.json +15 -0
  156. package/testing/conformance/03-new-dictionary/expected/.contentrain/content/marketing/ui-strings/en.json +5 -0
  157. package/testing/conformance/03-new-dictionary/expected/.contentrain/context.json +22 -0
  158. package/testing/conformance/03-new-dictionary/expected/.contentrain/meta/ui-strings/en.json +5 -0
  159. package/testing/conformance/03-new-dictionary/expected/.contentrain/models/ui-strings.json +7 -0
  160. package/testing/conformance/03-new-dictionary/scenario.json +19 -0
  161. package/testing/conformance/03-new-dictionary/setup/.contentrain/config.json +15 -0
  162. package/testing/conformance/03-new-dictionary/setup/.contentrain/models/ui-strings.json +7 -0
  163. package/testing/conformance/README.md +77 -0
  164. package/testing/conformance/scenarios.json +36 -0
  165. package/dist/config-B5kc2oeV.mjs +0 -27
  166. package/dist/config-B5kc2oeV.mjs.map +0 -1
  167. package/dist/context-DIDt_TxX.mjs +0 -46
  168. package/dist/context-DIDt_TxX.mjs.map +0 -1
  169. package/dist/core/content-manager.d.mts.map +0 -1
  170. package/dist/core/validator.d.mts +0 -23
  171. package/dist/core/validator.d.mts.map +0 -1
  172. package/dist/core/validator.mjs +0 -7
  173. package/dist/fs-BnIQ4dKj.mjs.map +0 -1
  174. package/dist/model-manager-DW_fOGRM.mjs.map +0 -1
  175. package/dist/serializer-CnHTtmc1.mjs +0 -2
  176. package/dist/server-Dtq8vqbK.mjs.map +0 -1
  177. package/dist/server.d.mts.map +0 -1
  178. package/dist/transaction-C_Pvux78.mjs.map +0 -1
  179. package/dist/tsx-parser-BFLv292Y.mjs +0 -2
  180. package/dist/util/serializer.d.mts +0 -2
  181. package/dist/util/serializer.mjs +0 -2
  182. package/dist/validator-SQYUV2JP.mjs +0 -581
  183. package/dist/validator-SQYUV2JP.mjs.map +0 -1
@@ -0,0 +1,40 @@
1
+ import { a as readJson, t as contentrainDir } from "./fs-DLbVB-Ek.mjs";
2
+ import { join } from "node:path";
3
+ //#region src/core/config.ts
4
+ const CONFIG_PATH = ".contentrain/config.json";
5
+ const VOCABULARY_PATH = ".contentrain/vocabulary.json";
6
+ async function readJsonViaReader(reader, path) {
7
+ try {
8
+ return JSON.parse(await reader.readFile(path));
9
+ } catch {
10
+ return null;
11
+ }
12
+ }
13
+ function normaliseConfig(raw) {
14
+ if (!raw) return null;
15
+ return {
16
+ version: raw.version ?? 1,
17
+ stack: raw.stack ?? "other",
18
+ workflow: raw.workflow ?? "auto-merge",
19
+ locales: {
20
+ default: raw.locales?.default ?? "en",
21
+ supported: raw.locales?.supported ?? [raw.locales?.default ?? "en"]
22
+ },
23
+ domains: raw.domains ?? [],
24
+ repository: raw.repository,
25
+ assets_path: raw.assets_path,
26
+ branchRetention: raw.branchRetention
27
+ };
28
+ }
29
+ async function readConfig(input) {
30
+ if (typeof input === "string") return normaliseConfig(await readJson(join(contentrainDir(input), "config.json")));
31
+ return normaliseConfig(await readJsonViaReader(input, CONFIG_PATH));
32
+ }
33
+ async function readVocabulary(input) {
34
+ if (typeof input === "string") return readJson(join(contentrainDir(input), "vocabulary.json"));
35
+ return readJsonViaReader(input, VOCABULARY_PATH);
36
+ }
37
+ //#endregion
38
+ export { readVocabulary as n, readConfig as t };
39
+
40
+ //# sourceMappingURL=config-BIl5Ybj0.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-BIl5Ybj0.mjs","names":[],"sources":["../src/core/config.ts"],"sourcesContent":["import type { ContentrainConfig, Vocabulary } from '@contentrain/types'\nimport { join } from 'node:path'\nimport { contentrainDir, readJson } from '../util/fs.js'\nimport type { RepoReader } from './contracts/index.js'\n\nconst CONFIG_PATH = '.contentrain/config.json'\nconst VOCABULARY_PATH = '.contentrain/vocabulary.json'\n\nasync function readJsonViaReader<T>(reader: RepoReader, path: string): Promise<T | null> {\n try {\n return JSON.parse(await reader.readFile(path)) as T\n } catch {\n return null\n }\n}\n\nfunction normaliseConfig(raw: Partial<ContentrainConfig> | null): ContentrainConfig | null {\n if (!raw) return null\n return {\n version: raw.version ?? 1,\n stack: raw.stack ?? 'other',\n workflow: raw.workflow ?? 'auto-merge',\n locales: {\n default: raw.locales?.default ?? 'en',\n supported: raw.locales?.supported ?? [raw.locales?.default ?? 'en'],\n },\n domains: raw.domains ?? [],\n repository: raw.repository,\n assets_path: raw.assets_path,\n branchRetention: raw.branchRetention,\n }\n}\n\n/**\n * Read `.contentrain/config.json` and normalise it with safe defaults.\n *\n * Accepts either a legacy `projectRoot` string (LocalReader is constructed\n * internally) or any `RepoReader` — tool handlers pass their provider so\n * the same logic resolves against local fs or the GitHub Git Data API.\n */\nexport function readConfig(projectRoot: string): Promise<ContentrainConfig | null>\nexport function readConfig(reader: RepoReader): Promise<ContentrainConfig | null>\nexport async function readConfig(input: string | RepoReader): Promise<ContentrainConfig | null> {\n if (typeof input === 'string') {\n const raw = await readJson<Partial<ContentrainConfig>>(join(contentrainDir(input), 'config.json'))\n return normaliseConfig(raw)\n }\n const raw = await readJsonViaReader<Partial<ContentrainConfig>>(input, CONFIG_PATH)\n return normaliseConfig(raw)\n}\n\n/**\n * Read `.contentrain/vocabulary.json`. Same dual signature as {@link readConfig}.\n */\nexport function readVocabulary(projectRoot: string): Promise<Vocabulary | null>\nexport function readVocabulary(reader: RepoReader): Promise<Vocabulary | null>\nexport async function readVocabulary(input: string | RepoReader): Promise<Vocabulary | null> {\n if (typeof input === 'string') {\n return readJson<Vocabulary>(join(contentrainDir(input), 'vocabulary.json'))\n }\n return readJsonViaReader<Vocabulary>(input, VOCABULARY_PATH)\n}\n"],"mappings":";;;AAKA,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAExB,eAAe,kBAAqB,QAAoB,MAAiC;AACvF,KAAI;AACF,SAAO,KAAK,MAAM,MAAM,OAAO,SAAS,KAAK,CAAC;SACxC;AACN,SAAO;;;AAIX,SAAS,gBAAgB,KAAkE;AACzF,KAAI,CAAC,IAAK,QAAO;AACjB,QAAO;EACL,SAAS,IAAI,WAAW;EACxB,OAAO,IAAI,SAAS;EACpB,UAAU,IAAI,YAAY;EAC1B,SAAS;GACP,SAAS,IAAI,SAAS,WAAW;GACjC,WAAW,IAAI,SAAS,aAAa,CAAC,IAAI,SAAS,WAAW,KAAK;GACpE;EACD,SAAS,IAAI,WAAW,EAAE;EAC1B,YAAY,IAAI;EAChB,aAAa,IAAI;EACjB,iBAAiB,IAAI;EACtB;;AAYH,eAAsB,WAAW,OAA+D;AAC9F,KAAI,OAAO,UAAU,SAEnB,QAAO,gBADK,MAAM,SAAqC,KAAK,eAAe,MAAM,EAAE,cAAc,CAAC,CACvE;AAG7B,QAAO,gBADK,MAAM,kBAA8C,OAAO,YAAY,CACxD;;AAQ7B,eAAsB,eAAe,OAAwD;AAC3F,KAAI,OAAO,UAAU,SACnB,QAAO,SAAqB,KAAK,eAAe,MAAM,EAAE,kBAAkB,CAAC;AAE7E,QAAO,kBAA8B,OAAO,gBAAgB"}
@@ -0,0 +1,63 @@
1
+ import { d as RepoReader } from "./index-D0wQJSgs.mjs";
2
+ import { ContentrainConfig, LocaleStrategy, ModelDefinition, Vocabulary, parseMarkdownFrontmatter as parseFrontmatter, serializeMarkdownFrontmatter as serializeFrontmatter, validateEntryId as validateEntryId$1, validateLocale as validateLocale$1, validateSlug as validateSlug$1 } from "@contentrain/types";
3
+
4
+ //#region src/core/content-manager.d.ts
5
+ declare function resolveContentDir(projectRoot: string, model: ModelDefinition): string;
6
+ declare function resolveLocaleStrategy(model: ModelDefinition): LocaleStrategy;
7
+ /** Build the file path for a JSON content file (singleton/collection/dictionary) */
8
+ declare function resolveJsonFilePath(dir: string, model: ModelDefinition, locale: string): string;
9
+ /** Build the file path for a markdown document */
10
+ declare function resolveMdFilePath(dir: string, model: ModelDefinition, locale: string, slug: string): string;
11
+ interface ContentEntry {
12
+ id?: string;
13
+ slug?: string;
14
+ locale?: string;
15
+ data: Record<string, unknown>;
16
+ }
17
+ interface WriteResult {
18
+ action: 'created' | 'updated';
19
+ id?: string;
20
+ slug?: string;
21
+ locale: string;
22
+ advisories?: string[];
23
+ }
24
+ interface DeleteOpts {
25
+ id?: string;
26
+ slug?: string;
27
+ locale?: string;
28
+ keys?: string[];
29
+ }
30
+ interface ListOpts {
31
+ locale?: string;
32
+ filter?: Record<string, unknown>;
33
+ resolve?: boolean;
34
+ limit?: number;
35
+ offset?: number;
36
+ }
37
+ declare function writeContent(projectRoot: string, model: ModelDefinition, entries: ContentEntry[], config: ContentrainConfig, vocabulary?: Vocabulary | null): Promise<WriteResult[]>;
38
+ declare function deleteContent(projectRoot: string, model: ModelDefinition, opts: DeleteOpts): Promise<string[]>;
39
+ /**
40
+ * List content entries for a model. Dual signature:
41
+ *
42
+ * - `listContent(projectRoot, model, opts, config)` — legacy local flow,
43
+ * uses direct filesystem reads and supports `opts.resolve` for
44
+ * cross-model relation hydration.
45
+ * - `listContent(reader, model, opts, config)` — reader-backed flow for
46
+ * remote providers. Basic list works across all four model kinds.
47
+ * `opts.resolve: true` is rejected with an error on remote readers
48
+ * because the cross-model walk requires local filesystem access.
49
+ *
50
+ * The reader-based function lives in {@link listContentViaReader}; the
51
+ * projectRoot-based entry point continues to call the legacy body to
52
+ * preserve bit-for-bit behaviour for every existing caller.
53
+ */
54
+ declare function listContent(projectRoot: string, model: ModelDefinition, opts: ListOpts, config: ContentrainConfig): Promise<unknown>;
55
+ declare function listContent(reader: RepoReader, model: ModelDefinition, opts: ListOpts, config: ContentrainConfig): Promise<unknown>;
56
+ declare function readContent(projectRoot: string, model: ModelDefinition, opts: {
57
+ locale: string;
58
+ entryId?: string;
59
+ slug?: string;
60
+ }): Promise<unknown>;
61
+ //#endregion
62
+ export { writeContent as _, deleteContent as a, readContent as c, resolveLocaleStrategy as d, resolveMdFilePath as f, validateSlug$1 as g, validateLocale$1 as h, WriteResult as i, resolveContentDir as l, validateEntryId$1 as m, DeleteOpts as n, listContent as o, serializeFrontmatter as p, ListOpts as r, parseFrontmatter as s, ContentEntry as t, resolveJsonFilePath as u };
63
+ //# sourceMappingURL=content-manager-DqDLSNQ-.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-manager-DqDLSNQ-.d.mts","names":[],"sources":["../src/core/content-manager.ts"],"mappings":";;;;iBAgBgB,iBAAA,CAAkB,WAAA,UAAqB,KAAA,EAAO,eAAA;AAAA,iBAO9C,qBAAA,CAAsB,KAAA,EAAO,eAAA,GAAkB,cAAA;;iBAK/C,mBAAA,CAAoB,GAAA,UAAa,KAAA,EAAO,eAAA,EAAiB,MAAA;;iBAczD,iBAAA,CAAkB,GAAA,UAAa,KAAA,EAAO,eAAA,EAAiB,MAAA,UAAgB,IAAA;AAAA,UAetE,YAAA;EACf,EAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA,EAAM,MAAA;AAAA;AAAA,UAGS,WAAA;EACf,MAAA;EACA,EAAA;EACA,IAAA;EACA,MAAA;EACA,UAAA;AAAA;AAAA,UAGe,UAAA;EACf,EAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;AAAA;AAAA,UAGe,QAAA;EACf,MAAA;EACA,MAAA,GAAS,MAAA;EACT,OAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,iBAsBoB,YAAA,CACpB,WAAA,UACA,KAAA,EAAO,eAAA,EACP,OAAA,EAAS,YAAA,IACT,MAAA,EAAQ,iBAAA,EACR,UAAA,GAAa,UAAA,UACZ,OAAA,CAAQ,WAAA;AAAA,iBAyIW,aAAA,CACpB,WAAA,UACA,KAAA,EAAO,eAAA,EACP,IAAA,EAAM,UAAA,GACL,OAAA;;;;;AApMH;;;;;;;;;;;iBAoUgB,WAAA,CACd,WAAA,UACA,KAAA,EAAO,eAAA,EACP,IAAA,EAAM,QAAA,EACN,MAAA,EAAQ,iBAAA,GACP,OAAA;AAAA,iBACa,WAAA,CACd,MAAA,EAAQ,UAAA,EACR,KAAA,EAAO,eAAA,EACP,IAAA,EAAM,QAAA,EACN,MAAA,EAAQ,iBAAA,GACP,OAAA;AAAA,iBA0QmB,WAAA,CACpB,WAAA,UACA,KAAA,EAAO,eAAA,EACP,IAAA;EAAQ,MAAA;EAAgB,OAAA;EAAkB,IAAA;AAAA,IACzC,OAAA"}
@@ -0,0 +1,102 @@
1
+ import { n as canonicalStringify } from "./serialization-B1CEzR4H.mjs";
2
+ import { a as readJson, s as writeJson, t as contentrainDir } from "./fs-DLbVB-Ek.mjs";
3
+ import { t as readConfig } from "./config-BIl5Ybj0.mjs";
4
+ import { o as listModels, r as countEntries, s as readModel } from "./model-manager-BhLsUgaB.mjs";
5
+ import { join } from "node:path";
6
+ //#region src/core/context.ts
7
+ const CONTEXT_PATH = ".contentrain/context.json";
8
+ async function readContext(input) {
9
+ if (typeof input === "string") return readJson(join(contentrainDir(input), "context.json"));
10
+ try {
11
+ const raw = await input.readFile(CONTEXT_PATH);
12
+ return JSON.parse(raw);
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function resolveSource(explicit) {
18
+ if (explicit) return explicit;
19
+ return process.env["CONTENTRAIN_SOURCE"] === "mcp-studio" ? "mcp-studio" : "mcp-local";
20
+ }
21
+ async function computeEntriesCount(projectRoot) {
22
+ try {
23
+ const models = await listModels(projectRoot);
24
+ const fullModels = await Promise.all(models.map((m) => readModel(projectRoot, m.id)));
25
+ return (await Promise.all(fullModels.filter((m) => m !== null).map((m) => countEntries(projectRoot, m)))).reduce((acc, c) => acc + c.total, 0);
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+ async function writeContext(projectRoot, operation) {
31
+ const models = await listModels(projectRoot);
32
+ const config = await readConfig(projectRoot);
33
+ const locales = config?.locales.supported ?? ["en"];
34
+ const totalEntries = await computeEntriesCount(projectRoot);
35
+ const source = resolveSource();
36
+ const context = {
37
+ version: "1",
38
+ lastOperation: {
39
+ tool: operation.tool,
40
+ model: operation.model,
41
+ locale: operation.locale ?? config?.locales.default ?? "en",
42
+ entries: operation.entries,
43
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
44
+ source
45
+ },
46
+ stats: {
47
+ models: models.length,
48
+ entries: totalEntries,
49
+ locales,
50
+ lastSync: (/* @__PURE__ */ new Date()).toISOString()
51
+ }
52
+ };
53
+ await writeJson(join(contentrainDir(projectRoot), "context.json"), context);
54
+ }
55
+ /**
56
+ * Build a FileChange for `.contentrain/context.json` that remote providers
57
+ * (GitHubProvider over HTTP, for example) can slot into their plan. The
58
+ * local write path still uses {@link writeContext} directly because its
59
+ * transaction layer writes into the post-apply worktree with real stats.
60
+ *
61
+ * Remote providers (Phase 5.5+) now also get accurate entry counts: the
62
+ * reader-based {@link countEntries} walks each model over the provider's
63
+ * read surface. GitHubProvider pays an extra round trip per model; the
64
+ * payoff is a context.json that matches what the local write path emits,
65
+ * so cross-provider merges stay deterministic.
66
+ */
67
+ async function buildContextChange(reader, operation, source) {
68
+ const config = await readConfig(reader);
69
+ const models = await listModels(reader);
70
+ const locales = config?.locales.supported ?? ["en"];
71
+ let totalEntries = null;
72
+ try {
73
+ const fullModels = await Promise.all(models.map((m) => readModel(reader, m.id)));
74
+ totalEntries = (await Promise.all(fullModels.filter((m) => m !== null).map((m) => countEntries(reader, m)))).reduce((acc, c) => acc + c.total, 0);
75
+ } catch {
76
+ totalEntries = null;
77
+ }
78
+ return {
79
+ path: CONTEXT_PATH,
80
+ content: canonicalStringify({
81
+ version: "1",
82
+ lastOperation: {
83
+ tool: operation.tool,
84
+ model: operation.model,
85
+ locale: operation.locale ?? config?.locales.default ?? "en",
86
+ entries: operation.entries,
87
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
88
+ source: resolveSource(source)
89
+ },
90
+ stats: {
91
+ models: models.length,
92
+ entries: totalEntries,
93
+ locales,
94
+ lastSync: (/* @__PURE__ */ new Date()).toISOString()
95
+ }
96
+ })
97
+ };
98
+ }
99
+ //#endregion
100
+ export { readContext as n, writeContext as r, buildContextChange as t };
101
+
102
+ //# sourceMappingURL=context-J0OU9Nfp.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-J0OU9Nfp.mjs","names":[],"sources":["../src/core/context.ts"],"sourcesContent":["import type { ContextJson, ContextSource } from '@contentrain/types'\nimport { join } from 'node:path'\nimport { contentrainDir, readJson, writeJson } from '../util/fs.js'\nimport type { FileChange, RepoReader } from './contracts/index.js'\nimport { canonicalStringify } from './serialization/index.js'\nimport { listModels, readModel, countEntries } from './model-manager.js'\nimport { readConfig } from './config.js'\n\nconst CONTEXT_PATH = '.contentrain/context.json'\n\n/**\n * Read the committed `.contentrain/context.json` payload written by the\n * most recent content or model operation. Returns `null` when the file\n * does not exist (fresh project, or reader lookup failure).\n *\n * Dual signature — the local flow passes a `projectRoot` string, remote\n * flows (GitHubProvider, GitLabProvider, any custom `RepoReader`) pass\n * the reader directly so `contentrain_status` over HTTP can still\n * report the last operation + stats.\n */\nexport function readContext(projectRoot: string): Promise<ContextJson | null>\nexport function readContext(reader: RepoReader): Promise<ContextJson | null>\nexport async function readContext(input: string | RepoReader): Promise<ContextJson | null> {\n if (typeof input === 'string') {\n return readJson<ContextJson>(join(contentrainDir(input), 'context.json'))\n }\n try {\n const raw = await input.readFile(CONTEXT_PATH)\n return JSON.parse(raw) as ContextJson\n } catch {\n return null\n }\n}\n\nfunction resolveSource(explicit?: ContextSource): ContextSource {\n if (explicit) return explicit\n return process.env['CONTENTRAIN_SOURCE'] === 'mcp-studio' ? 'mcp-studio' : 'mcp-local'\n}\n\nasync function computeEntriesCount(projectRoot: string): Promise<number | null> {\n try {\n const models = await listModels(projectRoot)\n const fullModels = await Promise.all(models.map(m => readModel(projectRoot, m.id)))\n const counts = await Promise.all(\n fullModels\n .filter((m): m is NonNullable<typeof m> => m !== null)\n .map(m => countEntries(projectRoot, m)),\n )\n return counts.reduce((acc, c) => acc + c.total, 0)\n } catch {\n return null\n }\n}\n\nexport async function writeContext(\n projectRoot: string,\n operation: { tool: string, model: string, locale?: string, entries?: string[] },\n): Promise<void> {\n const models = await listModels(projectRoot)\n const config = await readConfig(projectRoot)\n const locales = config?.locales.supported ?? ['en']\n const totalEntries = await computeEntriesCount(projectRoot)\n const source = resolveSource()\n\n const context: ContextJson = {\n version: '1',\n lastOperation: {\n tool: operation.tool,\n model: operation.model,\n locale: operation.locale ?? config?.locales.default ?? 'en',\n entries: operation.entries,\n timestamp: new Date().toISOString(),\n source,\n },\n stats: {\n models: models.length,\n entries: totalEntries as number,\n locales,\n lastSync: new Date().toISOString(),\n },\n }\n\n await writeJson(join(contentrainDir(projectRoot), 'context.json'), context)\n}\n\n/**\n * Build a FileChange for `.contentrain/context.json` that remote providers\n * (GitHubProvider over HTTP, for example) can slot into their plan. The\n * local write path still uses {@link writeContext} directly because its\n * transaction layer writes into the post-apply worktree with real stats.\n *\n * Remote providers (Phase 5.5+) now also get accurate entry counts: the\n * reader-based {@link countEntries} walks each model over the provider's\n * read surface. GitHubProvider pays an extra round trip per model; the\n * payoff is a context.json that matches what the local write path emits,\n * so cross-provider merges stay deterministic.\n */\nexport async function buildContextChange(\n reader: RepoReader,\n operation: { tool: string, model: string, locale?: string, entries?: string[] },\n source?: ContextSource,\n): Promise<FileChange> {\n const config = await readConfig(reader)\n const models = await listModels(reader)\n const locales = config?.locales.supported ?? ['en']\n\n let totalEntries: number | null = null\n try {\n const fullModels = await Promise.all(models.map(m => readModel(reader, m.id)))\n const counts = await Promise.all(\n fullModels\n .filter((m): m is NonNullable<typeof m> => m !== null)\n .map(m => countEntries(reader, m)),\n )\n totalEntries = counts.reduce((acc, c) => acc + c.total, 0)\n } catch {\n totalEntries = null\n }\n\n const context: ContextJson = {\n version: '1',\n lastOperation: {\n tool: operation.tool,\n model: operation.model,\n locale: operation.locale ?? config?.locales.default ?? 'en',\n entries: operation.entries,\n timestamp: new Date().toISOString(),\n source: resolveSource(source),\n },\n stats: {\n models: models.length,\n entries: totalEntries as number,\n locales,\n lastSync: new Date().toISOString(),\n },\n }\n\n return {\n path: CONTEXT_PATH,\n content: canonicalStringify(context),\n }\n}\n"],"mappings":";;;;;;AAQA,MAAM,eAAe;AAcrB,eAAsB,YAAY,OAAyD;AACzF,KAAI,OAAO,UAAU,SACnB,QAAO,SAAsB,KAAK,eAAe,MAAM,EAAE,eAAe,CAAC;AAE3E,KAAI;EACF,MAAM,MAAM,MAAM,MAAM,SAAS,aAAa;AAC9C,SAAO,KAAK,MAAM,IAAI;SAChB;AACN,SAAO;;;AAIX,SAAS,cAAc,UAAyC;AAC9D,KAAI,SAAU,QAAO;AACrB,QAAO,QAAQ,IAAI,0BAA0B,eAAe,eAAe;;AAG7E,eAAe,oBAAoB,aAA6C;AAC9E,KAAI;EACF,MAAM,SAAS,MAAM,WAAW,YAAY;EAC5C,MAAM,aAAa,MAAM,QAAQ,IAAI,OAAO,KAAI,MAAK,UAAU,aAAa,EAAE,GAAG,CAAC,CAAC;AAMnF,UALe,MAAM,QAAQ,IAC3B,WACG,QAAQ,MAAkC,MAAM,KAAK,CACrD,KAAI,MAAK,aAAa,aAAa,EAAE,CAAC,CAC1C,EACa,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,EAAE;SAC5C;AACN,SAAO;;;AAIX,eAAsB,aACpB,aACA,WACe;CACf,MAAM,SAAS,MAAM,WAAW,YAAY;CAC5C,MAAM,SAAS,MAAM,WAAW,YAAY;CAC5C,MAAM,UAAU,QAAQ,QAAQ,aAAa,CAAC,KAAK;CACnD,MAAM,eAAe,MAAM,oBAAoB,YAAY;CAC3D,MAAM,SAAS,eAAe;CAE9B,MAAM,UAAuB;EAC3B,SAAS;EACT,eAAe;GACb,MAAM,UAAU;GAChB,OAAO,UAAU;GACjB,QAAQ,UAAU,UAAU,QAAQ,QAAQ,WAAW;GACvD,SAAS,UAAU;GACnB,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC;GACD;EACD,OAAO;GACL,QAAQ,OAAO;GACf,SAAS;GACT;GACA,2BAAU,IAAI,MAAM,EAAC,aAAa;GACnC;EACF;AAED,OAAM,UAAU,KAAK,eAAe,YAAY,EAAE,eAAe,EAAE,QAAQ;;;;;;;;;;;;;;AAe7E,eAAsB,mBACpB,QACA,WACA,QACqB;CACrB,MAAM,SAAS,MAAM,WAAW,OAAO;CACvC,MAAM,SAAS,MAAM,WAAW,OAAO;CACvC,MAAM,UAAU,QAAQ,QAAQ,aAAa,CAAC,KAAK;CAEnD,IAAI,eAA8B;AAClC,KAAI;EACF,MAAM,aAAa,MAAM,QAAQ,IAAI,OAAO,KAAI,MAAK,UAAU,QAAQ,EAAE,GAAG,CAAC,CAAC;AAM9E,kBALe,MAAM,QAAQ,IAC3B,WACG,QAAQ,MAAkC,MAAM,KAAK,CACrD,KAAI,MAAK,aAAa,QAAQ,EAAE,CAAC,CACrC,EACqB,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,EAAE;SACpD;AACN,iBAAe;;AAqBjB,QAAO;EACL,MAAM;EACN,SAAS,mBApBkB;GAC3B,SAAS;GACT,eAAe;IACb,MAAM,UAAU;IAChB,OAAO,UAAU;IACjB,QAAQ,UAAU,UAAU,QAAQ,QAAQ,WAAW;IACvD,SAAS,UAAU;IACnB,4BAAW,IAAI,MAAM,EAAC,aAAa;IACnC,QAAQ,cAAc,OAAO;IAC9B;GACD,OAAO;IACL,QAAQ,OAAO;IACf,SAAS;IACT;IACA,2BAAU,IAAI,MAAM,EAAC,aAAa;IACnC;GACF,CAIqC;EACrC"}
@@ -0,0 +1,2 @@
1
+ import { LOCAL_CAPABILITIES } from "@contentrain/types";
2
+ export { LOCAL_CAPABILITIES as t };
@@ -1,11 +1,11 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import "../config-B5kc2oeV.mjs";
4
- import "../meta-manager--0IwAPCl.mjs";
5
- import "../model-manager-DW_fOGRM.mjs";
6
- import "../context-DIDt_TxX.mjs";
7
- import "../branch-lifecycle-wGJg25LT.mjs";
8
- import "../id-DV_T9Ic8.mjs";
9
- import "../transaction-C_Pvux78.mjs";
10
- import { a as detectFileFramework, c as validatePatchPath, i as checkSyntax, n as applyExtract, o as replaceInLine, r as applyReuse, s as validateFrameworkExpression, t as PATCHABLE_EXTENSIONS } from "../apply-manager-BkPMfpsN.mjs";
1
+ import "../serialization-B1CEzR4H.mjs";
2
+ import "../fs-DLbVB-Ek.mjs";
3
+ import "../config-BIl5Ybj0.mjs";
4
+ import "../model-manager-BhLsUgaB.mjs";
5
+ import "../meta-manager-C900rEyG.mjs";
6
+ import "../context-J0OU9Nfp.mjs";
7
+ import "../id-CIO9s0x_.mjs";
8
+ import "../transaction-DgkNgWSI.mjs";
9
+ import "../branch-lifecycle-CFVpTpNT.mjs";
10
+ import { a as detectFileFramework, c as validatePatchPath, i as checkSyntax, n as applyExtract, o as replaceInLine, r as applyReuse, s as validateFrameworkExpression, t as PATCHABLE_EXTENSIONS } from "../apply-manager-D5ym5Jba.mjs";
11
11
  export { PATCHABLE_EXTENSIONS, applyExtract, applyReuse, checkSyntax, detectFileFramework, replaceInLine, validateFrameworkExpression, validatePatchPath };
@@ -1,8 +1,21 @@
1
+ import { d as RepoReader } from "../index-D0wQJSgs.mjs";
1
2
  import { ContentrainConfig, Vocabulary } from "@contentrain/types";
2
3
 
3
4
  //#region src/core/config.d.ts
5
+ /**
6
+ * Read `.contentrain/config.json` and normalise it with safe defaults.
7
+ *
8
+ * Accepts either a legacy `projectRoot` string (LocalReader is constructed
9
+ * internally) or any `RepoReader` — tool handlers pass their provider so
10
+ * the same logic resolves against local fs or the GitHub Git Data API.
11
+ */
4
12
  declare function readConfig(projectRoot: string): Promise<ContentrainConfig | null>;
13
+ declare function readConfig(reader: RepoReader): Promise<ContentrainConfig | null>;
14
+ /**
15
+ * Read `.contentrain/vocabulary.json`. Same dual signature as {@link readConfig}.
16
+ */
5
17
  declare function readVocabulary(projectRoot: string): Promise<Vocabulary | null>;
18
+ declare function readVocabulary(reader: RepoReader): Promise<Vocabulary | null>;
6
19
  //#endregion
7
20
  export { readConfig, readVocabulary };
8
21
  //# sourceMappingURL=config.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../../src/core/config.ts"],"mappings":";;;iBAIsB,UAAA,CAAW,WAAA,WAAsB,OAAA,CAAQ,iBAAA;AAAA,iBAoBzC,cAAA,CAAe,WAAA,WAAsB,OAAA,CAAQ,UAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../../src/core/config.ts"],"mappings":";;;;;;AAwCA;;;;;iBAAgB,UAAA,CAAW,WAAA,WAAsB,OAAA,CAAQ,iBAAA;AAAA,iBACzC,UAAA,CAAW,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,iBAAA;;;AAAxD;iBAagB,cAAA,CAAe,WAAA,WAAsB,OAAA,CAAQ,UAAA;AAAA,iBAC7C,cAAA,CAAe,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA"}
@@ -1,4 +1,3 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import { n as readVocabulary, t as readConfig } from "../config-B5kc2oeV.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import { n as readVocabulary, t as readConfig } from "../config-BIl5Ybj0.mjs";
4
3
  export { readConfig, readVocabulary };
@@ -1,45 +1,2 @@
1
- import { ContentrainConfig, LocaleStrategy, ModelDefinition, parseMarkdownFrontmatter as parseFrontmatter, serializeMarkdownFrontmatter as serializeFrontmatter, validateEntryId, validateLocale, validateSlug } from "@contentrain/types";
2
-
3
- //#region src/core/content-manager.d.ts
4
- declare function resolveContentDir(projectRoot: string, model: ModelDefinition): string;
5
- declare function resolveLocaleStrategy(model: ModelDefinition): LocaleStrategy;
6
- /** Build the file path for a JSON content file (singleton/collection/dictionary) */
7
- declare function resolveJsonFilePath(dir: string, model: ModelDefinition, locale: string): string;
8
- /** Build the file path for a markdown document */
9
- declare function resolveMdFilePath(dir: string, model: ModelDefinition, locale: string, slug: string): string;
10
- interface ContentEntry {
11
- id?: string;
12
- slug?: string;
13
- locale?: string;
14
- data: Record<string, unknown>;
15
- }
16
- interface WriteResult {
17
- action: 'created' | 'updated';
18
- id?: string;
19
- slug?: string;
20
- locale: string;
21
- }
22
- interface DeleteOpts {
23
- id?: string;
24
- slug?: string;
25
- locale?: string;
26
- keys?: string[];
27
- }
28
- interface ListOpts {
29
- locale?: string;
30
- filter?: Record<string, unknown>;
31
- resolve?: boolean;
32
- limit?: number;
33
- offset?: number;
34
- }
35
- declare function writeContent(projectRoot: string, model: ModelDefinition, entries: ContentEntry[], config: ContentrainConfig): Promise<WriteResult[]>;
36
- declare function deleteContent(projectRoot: string, model: ModelDefinition, opts: DeleteOpts): Promise<string[]>;
37
- declare function listContent(projectRoot: string, model: ModelDefinition, opts: ListOpts, config: ContentrainConfig): Promise<unknown>;
38
- declare function readContent(projectRoot: string, model: ModelDefinition, opts: {
39
- locale: string;
40
- entryId?: string;
41
- slug?: string;
42
- }): Promise<unknown>;
43
- //#endregion
44
- export { ContentEntry, DeleteOpts, ListOpts, WriteResult, deleteContent, listContent, parseFrontmatter, readContent, resolveContentDir, resolveJsonFilePath, resolveLocaleStrategy, resolveMdFilePath, serializeFrontmatter, validateEntryId, validateLocale, validateSlug, writeContent };
45
- //# sourceMappingURL=content-manager.d.mts.map
1
+ import { _ as writeContent, a as deleteContent, c as readContent, d as resolveLocaleStrategy, f as resolveMdFilePath, g as validateSlug, h as validateLocale, i as WriteResult, l as resolveContentDir, m as validateEntryId, n as DeleteOpts, o as listContent, p as serializeFrontmatter, r as ListOpts, s as parseFrontmatter, t as ContentEntry, u as resolveJsonFilePath } from "../content-manager-DqDLSNQ-.mjs";
2
+ export { ContentEntry, DeleteOpts, ListOpts, WriteResult, deleteContent, listContent, parseFrontmatter, readContent, resolveContentDir, resolveJsonFilePath, resolveLocaleStrategy, resolveMdFilePath, serializeFrontmatter, validateEntryId, validateLocale, validateSlug, writeContent };
@@ -1,5 +1,4 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import "../meta-manager--0IwAPCl.mjs";
4
- import { S as writeContent, _ as resolveMdFilePath, b as validateLocale, d as listContent, f as parseFrontmatter, g as resolveLocaleStrategy, h as resolveJsonFilePath, m as resolveContentDir, p as readContent, u as deleteContent, v as serializeFrontmatter, x as validateSlug, y as validateEntryId } from "../model-manager-DW_fOGRM.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import { S as writeContent, _ as resolveMdFilePath, b as validateLocale, d as listContent, f as parseFrontmatter, g as resolveLocaleStrategy, h as resolveJsonFilePath, m as resolveContentDir, p as readContent, u as deleteContent, v as serializeFrontmatter, x as validateSlug, y as validateEntryId } from "../model-manager-BhLsUgaB.mjs";
3
+ import "../meta-manager-C900rEyG.mjs";
5
4
  export { deleteContent, listContent, parseFrontmatter, readContent, resolveContentDir, resolveJsonFilePath, resolveLocaleStrategy, resolveMdFilePath, serializeFrontmatter, validateEntryId, validateLocale, validateSlug, writeContent };
@@ -1,13 +1,43 @@
1
- import { ContextJson } from "@contentrain/types";
1
+ import { a as FileChange, d as RepoReader } from "../index-D0wQJSgs.mjs";
2
+ import { ContextJson, ContextSource } from "@contentrain/types";
2
3
 
3
4
  //#region src/core/context.d.ts
5
+ /**
6
+ * Read the committed `.contentrain/context.json` payload written by the
7
+ * most recent content or model operation. Returns `null` when the file
8
+ * does not exist (fresh project, or reader lookup failure).
9
+ *
10
+ * Dual signature — the local flow passes a `projectRoot` string, remote
11
+ * flows (GitHubProvider, GitLabProvider, any custom `RepoReader`) pass
12
+ * the reader directly so `contentrain_status` over HTTP can still
13
+ * report the last operation + stats.
14
+ */
4
15
  declare function readContext(projectRoot: string): Promise<ContextJson | null>;
16
+ declare function readContext(reader: RepoReader): Promise<ContextJson | null>;
5
17
  declare function writeContext(projectRoot: string, operation: {
6
18
  tool: string;
7
19
  model: string;
8
20
  locale?: string;
9
21
  entries?: string[];
10
22
  }): Promise<void>;
23
+ /**
24
+ * Build a FileChange for `.contentrain/context.json` that remote providers
25
+ * (GitHubProvider over HTTP, for example) can slot into their plan. The
26
+ * local write path still uses {@link writeContext} directly because its
27
+ * transaction layer writes into the post-apply worktree with real stats.
28
+ *
29
+ * Remote providers (Phase 5.5+) now also get accurate entry counts: the
30
+ * reader-based {@link countEntries} walks each model over the provider's
31
+ * read surface. GitHubProvider pays an extra round trip per model; the
32
+ * payoff is a context.json that matches what the local write path emits,
33
+ * so cross-provider merges stay deterministic.
34
+ */
35
+ declare function buildContextChange(reader: RepoReader, operation: {
36
+ tool: string;
37
+ model: string;
38
+ locale?: string;
39
+ entries?: string[];
40
+ }, source?: ContextSource): Promise<FileChange>;
11
41
  //#endregion
12
- export { readContext, writeContext };
42
+ export { buildContextChange, readContext, writeContext };
13
43
  //# sourceMappingURL=context.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.mts","names":[],"sources":["../../src/core/context.ts"],"mappings":";;;iBAMsB,WAAA,CAAY,WAAA,WAAsB,OAAA,CAAQ,WAAA;AAAA,iBAI1C,YAAA,CACpB,WAAA,UACA,SAAA;EAAa,IAAA;EAAc,KAAA;EAAe,MAAA;EAAiB,OAAA;AAAA,IAC1D,OAAA"}
1
+ {"version":3,"file":"context.d.mts","names":[],"sources":["../../src/core/context.ts"],"mappings":";;;;;;AAoBA;;;;;;;;iBAAgB,WAAA,CAAY,WAAA,WAAsB,OAAA,CAAQ,WAAA;AAAA,iBAC1C,WAAA,CAAY,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,WAAA;AAAA,iBAiCnC,YAAA,CACpB,WAAA,UACA,SAAA;EAAa,IAAA;EAAc,KAAA;EAAe,MAAA;EAAiB,OAAA;AAAA,IAC1D,OAAA;;;;;;;;AAHH;;;;;iBA2CsB,kBAAA,CACpB,MAAA,EAAQ,UAAA,EACR,SAAA;EAAa,IAAA;EAAc,KAAA;EAAe,MAAA;EAAiB,OAAA;AAAA,GAC3D,MAAA,GAAS,aAAA,GACR,OAAA,CAAQ,UAAA"}
@@ -1,7 +1,7 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import "../config-B5kc2oeV.mjs";
4
- import "../meta-manager--0IwAPCl.mjs";
5
- import "../model-manager-DW_fOGRM.mjs";
6
- import { n as writeContext, t as readContext } from "../context-DIDt_TxX.mjs";
7
- export { readContext, writeContext };
1
+ import "../serialization-B1CEzR4H.mjs";
2
+ import "../fs-DLbVB-Ek.mjs";
3
+ import "../config-BIl5Ybj0.mjs";
4
+ import "../model-manager-BhLsUgaB.mjs";
5
+ import "../meta-manager-C900rEyG.mjs";
6
+ import { n as readContext, r as writeContext, t as buildContextChange } from "../context-J0OU9Nfp.mjs";
7
+ export { buildContextChange, readContext, writeContext };
@@ -0,0 +1,2 @@
1
+ import { a as FileChange, c as MergeResult, d as RepoReader, f as RepoWriter, i as CommitAuthor, l as ProviderCapabilities, n as Branch, o as FileDiff, r as Commit, s as LOCAL_CAPABILITIES, t as ApplyPlanInput, u as RepoProvider } from "../../index-D0wQJSgs.mjs";
2
+ export { ApplyPlanInput, Branch, Commit, CommitAuthor, FileChange, FileDiff, LOCAL_CAPABILITIES, MergeResult, ProviderCapabilities, RepoProvider, RepoReader, RepoWriter };
@@ -0,0 +1,2 @@
1
+ import { t as LOCAL_CAPABILITIES } from "../../contracts-DfL0BfrD.mjs";
2
+ export { LOCAL_CAPABILITIES };
@@ -0,0 +1,76 @@
1
+ //#region src/core/doctor.d.ts
2
+ /**
3
+ * Doctor — project health report.
4
+ *
5
+ * The public entry point is `runDoctor(projectRoot, { usage? })`. It is
6
+ * inherently local-filesystem work (Node version, git install, file
7
+ * mtimes, orphan directory detection), so the MCP tool surface gates
8
+ * it behind the `localWorktree` capability — same pattern as
9
+ * `contentrain_setup` and normalize.
10
+ *
11
+ * The report is structured JSON so three consumers can share it:
12
+ *
13
+ * - The `contentrain doctor` CLI command pretty-prints the checks.
14
+ * - The Serve UI `/api/doctor` route returns the report to the
15
+ * Dashboard's Doctor panel.
16
+ * - Automation (CI, Studio) gets a deterministic JSON shape it can
17
+ * assert against.
18
+ *
19
+ * Usage analysis (`--usage`) is a heavier, opt-in branch — it scans
20
+ * every source file in the repo for content-key references. Kept
21
+ * behind the flag so the default doctor run stays fast.
22
+ */
23
+ type CheckSeverity = 'error' | 'warning' | 'info';
24
+ interface DoctorCheck {
25
+ name: string;
26
+ pass: boolean;
27
+ detail: string;
28
+ /**
29
+ * `error` — default for failing checks. Blocks a clean bill of health.
30
+ * `warning` — failing-but-not-blocking (e.g. pending branches above
31
+ * threshold, stale SDK client).
32
+ * `info` — passed check; pure informational.
33
+ */
34
+ severity?: CheckSeverity;
35
+ }
36
+ interface UnusedKeyEntry {
37
+ model: string;
38
+ kind: string;
39
+ key: string;
40
+ locale: string;
41
+ }
42
+ interface DuplicateValueEntry {
43
+ model: string;
44
+ locale: string;
45
+ value: string;
46
+ keys: string[];
47
+ }
48
+ interface MissingLocaleEntry {
49
+ model: string;
50
+ key: string;
51
+ missingIn: string;
52
+ }
53
+ interface DoctorUsageAnalysis {
54
+ unusedKeys: UnusedKeyEntry[];
55
+ duplicateValues: DuplicateValueEntry[];
56
+ missingLocaleKeys: MissingLocaleEntry[];
57
+ }
58
+ interface DoctorReport {
59
+ checks: DoctorCheck[];
60
+ summary: {
61
+ total: number;
62
+ passed: number;
63
+ failed: number;
64
+ warnings: number;
65
+ };
66
+ /** Present only when `options.usage === true`. */
67
+ usage?: DoctorUsageAnalysis;
68
+ }
69
+ interface RunDoctorOptions {
70
+ /** Run heavier `--usage` analysis (unused keys, duplicates, locale gaps). */
71
+ usage?: boolean;
72
+ }
73
+ declare function runDoctor(projectRoot: string, options?: RunDoctorOptions): Promise<DoctorReport>;
74
+ //#endregion
75
+ export { CheckSeverity, DoctorCheck, DoctorReport, DoctorUsageAnalysis, DuplicateValueEntry, MissingLocaleEntry, RunDoctorOptions, UnusedKeyEntry, runDoctor };
76
+ //# sourceMappingURL=doctor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.mts","names":[],"sources":["../../src/core/doctor.ts"],"mappings":";;AAiCA;;;;;AAEA;;;;;;;;;;;AAaA;;;;KAfY,aAAA;AAAA,UAEK,WAAA;EACf,IAAA;EACA,IAAA;EACA,MAAA;EAcM;AAGR;;;;;EAVE,QAAA,GAAW,aAAA;AAAA;AAAA,UAGI,cAAA;EACf,KAAA;EACA,IAAA;EACA,GAAA;EACA,MAAA;AAAA;AAAA,UAGe,mBAAA;EACf,KAAA;EACA,MAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,UAGe,kBAAA;EACf,KAAA;EACA,GAAA;EACA,SAAA;AAAA;AAAA,UAGe,mBAAA;EACf,UAAA,EAAY,cAAA;EACZ,eAAA,EAAiB,mBAAA;EACjB,iBAAA,EAAmB,kBAAA;AAAA;AAAA,UAGJ,YAAA;EACf,MAAA,EAAQ,WAAA;EACR,OAAA;IACE,KAAA;IACA,MAAA;IACA,MAAA;IACA,QAAA;EAAA;;EAGF,KAAA,GAAQ,mBAAA;AAAA;AAAA,UAGO,gBAAA;EAVf;EAYA,KAAA;AAAA;AAAA,iBAGoB,SAAA,CACpB,WAAA,UACA,OAAA,GAAS,gBAAA,GACR,OAAA,CAAQ,YAAA"}
@@ -0,0 +1,8 @@
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import "../config-BIl5Ybj0.mjs";
3
+ import "../model-manager-BhLsUgaB.mjs";
4
+ import "../meta-manager-C900rEyG.mjs";
5
+ import "../branch-lifecycle-CFVpTpNT.mjs";
6
+ import "../scan-config-jC6XmiqF.mjs";
7
+ import { t as runDoctor } from "../doctor-CgBoT6h1.mjs";
8
+ export { runDoctor };
@@ -1,5 +1,4 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import "../scan-config-QgnJ1-52.mjs";
4
- import { t as buildGraph } from "../graph-builder-tM7zj-SX.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import "../scan-config-jC6XmiqF.mjs";
3
+ import { t as buildGraph } from "../graph-builder-DXv2JEp-.mjs";
5
4
  export { buildGraph };
@@ -1,4 +1,3 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import { n as readMeta, r as writeMeta, t as deleteMeta } from "../meta-manager--0IwAPCl.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import { n as readMeta, r as writeMeta, t as deleteMeta } from "../meta-manager-C900rEyG.mjs";
4
3
  export { deleteMeta, readMeta, writeMeta };
@@ -1,13 +1,37 @@
1
- import { z } from "zod";
1
+ import { d as RepoReader } from "../index-D0wQJSgs.mjs";
2
2
  import { ModelDefinition, ModelSummary, ModelSummary as ModelSummary$1 } from "@contentrain/types";
3
+ import { z } from "zod";
3
4
 
4
5
  //#region src/core/model-manager.d.ts
6
+ /**
7
+ * List every model defined under `.contentrain/models/*.json`.
8
+ *
9
+ * Accepts either a legacy `projectRoot` string (filesystem walk) or any
10
+ * `RepoReader` — HTTP-hosted callers pass their `GitHubProvider` so the
11
+ * same helper resolves model metadata over the Git Data API.
12
+ */
5
13
  declare function listModels(projectRoot: string): Promise<ModelSummary$1[]>;
14
+ declare function listModels(reader: RepoReader): Promise<ModelSummary$1[]>;
15
+ /**
16
+ * Read a single model definition. Same dual signature as {@link listModels}.
17
+ */
6
18
  declare function readModel(projectRoot: string, modelId: string): Promise<ModelDefinition | null>;
19
+ declare function readModel(reader: RepoReader, modelId: string): Promise<ModelDefinition | null>;
20
+ /**
21
+ * Count content entries across locales for a model.
22
+ *
23
+ * Accepts either a legacy `projectRoot` string (wraps LocalReader internally)
24
+ * or any `RepoReader` — so remote providers (GitHubProvider) feed the same
25
+ * counting logic via the Git Data API.
26
+ */
7
27
  declare function countEntries(projectRoot: string, model: ModelDefinition): Promise<{
8
28
  total: number;
9
29
  locales: Record<string, number>;
10
30
  }>;
31
+ declare function countEntries(reader: RepoReader, model: ModelDefinition): Promise<{
32
+ total: number;
33
+ locales: Record<string, number>;
34
+ }>;
11
35
  declare function writeModel(projectRoot: string, model: ModelDefinition): Promise<void>;
12
36
  declare function deleteModel(projectRoot: string, modelId: string): Promise<string[]>;
13
37
  interface ModelReference {
@@ -15,7 +39,16 @@ interface ModelReference {
15
39
  field: string;
16
40
  type: 'relation' | 'relations';
17
41
  }
42
+ /**
43
+ * Enumerate models that reference `modelId` through relation or relations
44
+ * fields. Used by `model_delete` to block destructive deletes when other
45
+ * models still depend on the target.
46
+ *
47
+ * Accepts either a legacy `projectRoot` string (LocalReader wraps internally)
48
+ * or any `RepoReader` — remote providers get the same pre-check.
49
+ */
18
50
  declare function checkReferences(projectRoot: string, modelId: string): Promise<ModelReference[]>;
51
+ declare function checkReferences(reader: RepoReader, modelId: string): Promise<ModelReference[]>;
19
52
  declare const FIELD_TYPE_ENUM: readonly ["string", "text", "email", "url", "slug", "color", "phone", "code", "icon", "markdown", "richtext", "number", "integer", "decimal", "percent", "rating", "boolean", "date", "datetime", "image", "video", "file", "relation", "relations", "select", "array", "object"];
20
53
  /**
21
54
  * Shared Zod schema for field definitions.
@@ -1 +1 @@
1
- {"version":3,"file":"model-manager.d.mts","names":[],"sources":["../../src/core/model-manager.ts"],"mappings":";;;;iBASsB,UAAA,CAAW,WAAA,WAAsB,OAAA,CAAQ,cAAA;AAAA,iBAqBzC,SAAA,CAAU,WAAA,UAAqB,OAAA,WAAkB,OAAA,CAAQ,eAAA;AAAA,iBA6IzD,YAAA,CACpB,WAAA,UACA,KAAA,EAAO,eAAA,GACN,OAAA;EAAU,KAAA;EAAe,OAAA,EAAS,MAAA;AAAA;AAAA,iBA2Hf,UAAA,CAAW,WAAA,UAAqB,KAAA,EAAO,eAAA,GAAkB,OAAA;AAAA,iBASzD,WAAA,CAAY,WAAA,UAAqB,OAAA,WAAkB,OAAA;AAAA,UA+BxD,cAAA;EACf,KAAA;EACA,KAAA;EACA,IAAA;AAAA;AAAA,iBAGoB,eAAA,CAAgB,WAAA,UAAqB,OAAA,WAAkB,OAAA,CAAQ,cAAA;AAAA,cA0BxE,eAAA;;;;;cAcA,iBAAA,EAAmB,CAAA,CAAE,OAAA,CAAQ,MAAA;AApN1C;;;;;AAAA,iBAqPgB,uBAAA,CAAwB,KAAA;EAAS,EAAA;EAAY,IAAA;EAAc,MAAA,GAAS,MAAA;AAAA"}
1
+ {"version":3,"file":"model-manager.d.mts","names":[],"sources":["../../src/core/model-manager.ts"],"mappings":";;;;;;AA6BA;;;;;;iBAAgB,UAAA,CAAW,WAAA,WAAsB,OAAA,CAAQ,cAAA;AAAA,iBACzC,UAAA,CAAW,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,cAAA;;AAAxD;;iBAgCgB,SAAA,CAAU,WAAA,UAAqB,OAAA,WAAkB,OAAA,CAAQ,eAAA;AAAA,iBACzD,SAAA,CAAU,MAAA,EAAQ,UAAA,EAAY,OAAA,WAAkB,OAAA,CAAQ,eAAA;;;;;;;;iBA4JxD,YAAA,CACd,WAAA,UACA,KAAA,EAAO,eAAA,GACN,OAAA;EAAU,KAAA;EAAe,OAAA,EAAS,MAAA;AAAA;AAAA,iBACrB,YAAA,CACd,MAAA,EAAQ,UAAA,EACR,KAAA,EAAO,eAAA,GACN,OAAA;EAAU,KAAA;EAAe,OAAA,EAAS,MAAA;AAAA;AAAA,iBAgIf,UAAA,CAAW,WAAA,UAAqB,KAAA,EAAO,eAAA,GAAkB,OAAA;AAAA,iBASzD,WAAA,CAAY,WAAA,UAAqB,OAAA,WAAkB,OAAA;AAAA,UA+BxD,cAAA;EACf,KAAA;EACA,KAAA;EACA,IAAA;AAAA;;;;;;;;;iBAWc,eAAA,CAAgB,WAAA,UAAqB,OAAA,WAAkB,OAAA,CAAQ,cAAA;AAAA,iBAC/D,eAAA,CAAgB,MAAA,EAAQ,UAAA,EAAY,OAAA,WAAkB,OAAA,CAAQ,cAAA;AAAA,cA8BjE,eAAA;;;AA5Nb;;cA0Oa,iBAAA,EAAmB,CAAA,CAAE,OAAA,CAAQ,MAAA;;;;;;iBAiC1B,uBAAA,CAAwB,KAAA;EAAS,EAAA;EAAY,IAAA;EAAc,MAAA,GAAS,MAAA;AAAA"}
@@ -1,5 +1,4 @@
1
- import "../serializer-CnHTtmc1.mjs";
2
- import "../fs-BnIQ4dKj.mjs";
3
- import "../meta-manager--0IwAPCl.mjs";
4
- import { a as fieldDefZodSchema, c as validateModelDefinition, i as deleteModel, l as writeModel, n as checkReferences, o as listModels, r as countEntries, s as readModel, t as FIELD_TYPE_ENUM } from "../model-manager-DW_fOGRM.mjs";
1
+ import "../fs-DLbVB-Ek.mjs";
2
+ import { a as fieldDefZodSchema, c as validateModelDefinition, i as deleteModel, l as writeModel, n as checkReferences, o as listModels, r as countEntries, s as readModel, t as FIELD_TYPE_ENUM } from "../model-manager-BhLsUgaB.mjs";
3
+ import "../meta-manager-C900rEyG.mjs";
5
4
  export { FIELD_TYPE_ENUM, checkReferences, countEntries, deleteModel, fieldDefZodSchema, listModels, readModel, validateModelDefinition, writeModel };