@blinkk/root-cms 3.0.1-beta.5 → 3.0.1-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getServerVersion,
3
3
  serializeAiConfig
4
- } from "./chunk-5CZBPART.js";
4
+ } from "./chunk-VBIIJ22U.js";
5
5
  import "./chunk-C245C557.js";
6
6
  import "./chunk-2BSW7SIH.js";
7
7
  import {
@@ -191,7 +191,7 @@ function createCmsTools(ctx) {
191
191
  }
192
192
  }),
193
193
  doc_set: tool({
194
- description: "Replace the entire draft fields payload of a CMS document. Pass the full JSON object that should become the new draft contents \u2014 any fields omitted will be removed. The payload is validated against the collection schema and the call is rejected on validation errors. Prefer `doc_updateField` for targeted edits. Only writes the draft version; users must publish separately. Always confirm with the user before calling.",
194
+ description: "Replace the entire draft fields payload of a CMS document. Pass the full JSON object that should become the new draft contents \u2014 any fields omitted will be removed. The payload is validated against the collection schema and the call is rejected on validation errors. Prefer `doc_updateField` for targeted edits. Only writes the draft version; users must publish separately. Always confirm with the user before calling. Format: pass plain JSON. Arrays must be plain JSON arrays \u2014 do NOT use the `_array` object notation. The tool marshals the payload into Firestore storage shape on its own. Rich text fields use the `{version, time, blocks}` shape with `blocks` as a plain JSON array of `{type, data}` objects.",
195
195
  inputSchema: z.object({
196
196
  docId: z.string().describe(
197
197
  'Full doc id in the form "Collection/slug" (e.g. "Pages/home").'
@@ -202,7 +202,7 @@ function createCmsTools(ctx) {
202
202
  })
203
203
  }),
204
204
  doc_create: tool({
205
- description: "Create a new draft CMS document with the given slug. Fails if the doc already exists. Pass optional initial fields (validated against the collection schema). Always confirm with the user before calling.",
205
+ description: "Create a new draft CMS document with the given slug. Fails if the doc already exists. Pass optional initial fields (validated against the collection schema). Always confirm with the user before calling. Format: pass plain JSON for `fields`. Arrays must be plain JSON arrays \u2014 do NOT use the `_array` object notation. The tool marshals the payload into Firestore storage shape on its own. Rich text fields use the `{version, time, blocks}` shape with `blocks` as a plain JSON array of `{type, data}` objects.",
206
206
  inputSchema: z.object({
207
207
  docId: z.string().describe(
208
208
  'Full doc id in the form "Collection/slug" (e.g. "BlogPosts/my-new-post").'
@@ -211,7 +211,7 @@ function createCmsTools(ctx) {
211
211
  })
212
212
  }),
213
213
  doc_updateField: tool({
214
- description: 'Update a single field on a draft CMS document by JSON path. Paths are relative to the doc fields object; do not prefix them with "fields.". Use dotted paths (e.g. "hero.title") and zero-based array indices. For example, update the first module title with path "content.modules.0.title". To append or remove array items, first read the current doc, then set the whole array path (e.g. "content.modules") to the updated array. The value is validated against the field schema and the call is rejected if the shape is wrong (e.g. passing a string to a richtext field). Only updates the draft version; users must publish separately. Always confirm with the user before calling.',
214
+ description: 'Update a single field on a draft CMS document by JSON path. Paths are relative to the doc fields object; do not prefix them with "fields.". Use dotted paths (e.g. "hero.title") and zero-based array indices. For example, update the first module title with path "content.modules.0.title". To append or remove array items, first read the current doc, then set the whole array path (e.g. "content.modules") to the updated array. The value is validated against the field schema and the call is rejected if the shape is wrong (e.g. passing a string to a richtext field). Only updates the draft version; users must publish separately. Always confirm with the user before calling. Format: pass `value` as plain JSON. Arrays must be plain JSON arrays \u2014 do NOT use the `_array` object notation. The tool marshals the value into Firestore storage shape on its own. Rich text fields use the `{version, time, blocks}` shape and `blocks` MUST be a plain JSON array of `{type, data}` objects (never wrapped in `_array`).',
215
215
  inputSchema: z.object({
216
216
  docId: z.string(),
217
217
  path: z.string().describe(
@@ -625,6 +625,14 @@ function buildCmsToolContext(options) {
625
625
  }
626
626
  };
627
627
  }
628
+ function buildActiveDocPrompt(docId) {
629
+ return [
630
+ "Active document context:",
631
+ `- The user is currently viewing and editing the document \`${docId}\` in the CMS UI.`,
632
+ '- When the user refers to "this document", "this draft", "the current doc/page", or similar without naming a doc, they mean this document.',
633
+ "- Default to targeting this document for read and write tools unless the user explicitly names a different one."
634
+ ].join("\n");
635
+ }
628
636
  function buildExecutionModePrompt(mode) {
629
637
  const common = [
630
638
  "Root AI execution workflow:",
@@ -675,6 +683,7 @@ async function runChatStream(options) {
675
683
  user,
676
684
  chatId,
677
685
  executionMode = "approve",
686
+ activeDocId,
678
687
  loadCollection,
679
688
  loadAllCollections
680
689
  } = options;
@@ -694,10 +703,11 @@ async function runChatStream(options) {
694
703
  "Be concise and use markdown for rich responses."
695
704
  ].join(" ");
696
705
  const rootMd = await readRootMd(rootConfig.rootDir);
697
- const systemPrompt = buildSystemPrompt(
698
- [basePrompt, "", buildExecutionModePrompt(executionMode)].join("\n"),
699
- rootMd
700
- );
706
+ const promptSections = [basePrompt, "", buildExecutionModePrompt(executionMode)];
707
+ if (activeDocId) {
708
+ promptSections.push("", buildActiveDocPrompt(activeDocId));
709
+ }
710
+ const systemPrompt = buildSystemPrompt(promptSections.join("\n"), rootMd);
701
711
  const modelMessages = await convertToModelMessages(messages, { tools });
702
712
  const result = streamText({
703
713
  model: languageModel,
@@ -749,7 +759,7 @@ async function runEditObjectStream(options) {
749
759
  loadAllCollections
750
760
  });
751
761
  const tools = model.capabilities?.tools === false ? {} : createReadOnlyCmsTools(toolContext);
752
- const editPromptText = (await import("./edit-XX3LAGK6.js")).default;
762
+ const editPromptText = (await import("./edit-MT4B37QK.js")).default;
753
763
  const promptParts = [
754
764
  stripLegacyEditOutputSpec(editPromptText),
755
765
  "",
@@ -1003,7 +1013,7 @@ function extractJsonFromResponse(responseText) {
1003
1013
  // package.json
1004
1014
  var package_default = {
1005
1015
  name: "@blinkk/root-cms",
1006
- version: "3.0.1-beta.5",
1016
+ version: "3.0.1-beta.6",
1007
1017
  author: "s@blinkk.com",
1008
1018
  license: "MIT",
1009
1019
  engines: {
@@ -1172,7 +1182,7 @@ var package_default = {
1172
1182
  yjs: "13.6.27"
1173
1183
  },
1174
1184
  peerDependencies: {
1175
- "@blinkk/root": "3.0.1-beta.5",
1185
+ "@blinkk/root": "3.0.1-beta.6",
1176
1186
  "firebase-admin": ">=11",
1177
1187
  "firebase-functions": ">=4"
1178
1188
  },
@@ -0,0 +1,7 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // shared/ai/prompts/edit.txt
4
+ var edit_default = 'Role: You are a highly accurate AI assistant specializing in converting unstructured documents into JSON files compatible with Root CMS. Root CMS is a web-based CMS for building websites and landing pages, storing its content as JSON files in a Firebase Firestore database.\n\nObjective: To edit and/or generate highly accurate JSON files compatible with Root CMS, based on user input (screenshots, chat messages, etc.) and, when editing JSON files, the original JSON file you are editing. The resulting content should contain all of the marketing content provided by the user input (and none of the annotations or superfluous content). The JSON files should be perfectly compatible with Root CMS.\n\nInput Requirements & Handling:\n\n- You will receive unstructured documents and you must convert them into JSON files compatible with Root CMS by either editing the existing JSON files or generating new ones from scratch. The JSON files you produce will typically represent a single section of a page of the website, such as a hero section, a feature section, or a footer.\n\n- When editing an existing JSON file, it will be annotated with a key `_type` that indicates the type of section it is, such as `Hero`, `Feature`, or `Footer`. You must ensure that the resulting JSON file is compatible with Root CMS and contains all of the marketing content provided by the user input. You will also be given a TypeScript interface in `root-cms.d.ts` that describes the structure of the JSON file you are editing. You must ensure that the resulting JSON file is compatible with this interface.\n\n- The input you receive will be broken into three parts. (1) `root-cms-d.ts` (the TypeScript interface), (2) the existing JSON file you are editing (or an empty JSON file when generating new content), and (3) the user input (screenshots, chat messages, instructions, etc.). You must ensure that the resulting JSON file is compatible with the structure defined by the TypeScript interface and contains all of the marketing content provided by the user input.\n\n- When you provide your response, if the user instructs you to only edit one part of the original JSON, make sure to leave the rest of the JSON file untouched. You must return the entire JSON document after applying changes. Never omit, rename, reorder or invent top-level keys. Copy all unmodified fields exactly as they appear in the input.\n\nRoot CMS JSON File Structure:\n\n- Root CMS JSON files are standard JSON files described by the TypeScript interface in `root-cms.d.ts`. However, there is one critical syntax rule that you must understand and always follow regarding array values. Array values are expressed as hash maps. The order of the resulting data when Root CMS unmarshals the data is provided by a special key called `_array`. For example, to represent an array [1, 2, 3] in the CMS, the JSON data may look like this. You may generate your own UIDs for the keys and the items within `_array`.\n\n```json\n{\n "_array": ["2HGwoV", "LjFHWk", "OLakGA", "UaGHJh"],\n "2HGwoV": 1,\n "LjFHWk": 2,\n "OLakGA": 3,\n "UaGHJh": 4\n}\n```\n\nWhen creating arrays in your JSON output, you must _never_ forget to add an `_array` key. If you forget to add an `_array` key, the output will NOT work with Root CMS. When adding new array items, you can create your own array keys.\n\nThe ONE exception to this rule is the `blocks` array inside a Rich Text field (see #3 below). Rich Text data is stored as-is and is NOT marshaled, so `blocks` MUST always be a plain JSON array, never an `_array` object. Wrapping rich text `blocks` in `_array` notation will corrupt the data when it is saved.\n\n2. Images and file fields have system-provided metadata, that looks like this example:\n\n```\n{\n "src": "https://storage.googleapis.com/rootjs-dev.appspot.com/www/uploads/2cad5d65bb7690bad5dcd4a041cf2fef46361678.svg",\n "filename": "600x400.svg",\n "uploadedAt": "1754023634564",\n "alt": "",\n "width": "600",\n "uploadedBy": "user@example.com",\n "height": "400"\n}\n```\n\n3. Rich Text fields are stored as Editor.js / Lexical documents, which look like this. You may generate your own UIDs for the `id` fields. Note that `blocks` MUST be a plain JSON array \u2014 do NOT use the `_array` object notation here.\n\n```\n{\n "version": "2.28.2",\n "time": 1754024041637,\n "blocks": [\n {\n "type": "paragraph",\n "data": {\n "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <a href=\\"https://example.com\\">This accepts HTML</a>."\n },\n "id": "_8PEf3kBx2"\n },\n {\n "data": {\n "style": "unordered",\n "items": [\n {\n "content": "This is list item 1.",\n "items": []\n },\n {\n "items": [],\n "content": "This is list item 2."\n }\n ]\n },\n "id": "G5zMDP1ytM",\n "type": "unorderedList"\n }\n ]\n}\n```\n\n4. Root CMS supports "oneOf" fields, where values can be "one of" another schema. These are typically used as array values or object values, where the user can from one of other schema types to structure the data value. For example, each module in a page\'s module list is "one of" the modules available in the library. One of values have a system-provided `_type` key that describes the type of the value. For example, this is a hero module, whose type is "TemplateHeadline", one of the available templates from the module library:\n\n```\n{\n "eyebrow": "Lorem ipsum",\n "_type": "TemplateHeadline",\n "body": {\n "time": 1754023554170,\n "version": "2.28.2",\n "blocks": [\n {\n "type": "paragraph",\n "data": {\n "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."\n },\n "id": "IVmxEVsxmt"\n },\n {\n "id": "aMiHiywkQD",\n "type": "paragraph",\n "data": {\n "text": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."\n }\n }\n ]\n },\n "title": "Welcome to our website"\n}\n```\n\nWhen adding new items to arrays that use `oneOf` fields, try your best to figure out which content type would best satisfy the user\'s request. You must never _invent_ new content types, for example, if "TemplateFoo" doesn\'t exist in `root-cms.d.ts`, you must never add a value with `{"_type": "TemplateFoo"}`. If none of the available content types within `root-cms.d.ts` satisfy the user\'s request, avoid creating the new array item and inform the user that there is no existing template compatible.\n\nAdditionally, when adding new items to existing JSON data, you must carefully check the structure of those items as defined by `root-cms.d.ts`. Avoid inventing new fields for content types, use only those defined by the `root-cms.d.ts`. For example, if you are adding a button to a module, carefully check the button structure defined in `root-cms.d.ts` and only populate fields that are defined there.\n\nFinally, when you provide your response, it MUST be structured in the following way for handling by the chat client.\n\n{\n "data": <The JSON data generated by you via the instructions above>,\n "message": <A brief message that describes what you did.>\n}\n\nYou must always ONLY reply in this exact format. The brief message that describes what you did should be written succinctly, tersely, in a friendly but not cute tone, and be no more than a sentence or two.\n';
5
+ export {
6
+ edit_default as default
7
+ };
package/dist/plugin.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  serializeAiConfig,
13
13
  summarizeDiff,
14
14
  translateString
15
- } from "./chunk-5CZBPART.js";
15
+ } from "./chunk-VBIIJ22U.js";
16
16
  import {
17
17
  runCronJobs
18
18
  } from "./chunk-BGTUWIV6.js";
@@ -553,6 +553,7 @@ function api(server, options) {
553
553
  return;
554
554
  }
555
555
  const executionMode = normalizeExecutionMode(body.executionMode);
556
+ const activeDocId = typeof body.docId === "string" && body.docId.trim() ? body.docId.trim() : void 0;
556
557
  const cmsClient = new RootCMSClient(req.rootConfig);
557
558
  const store = new ChatStore(cmsClient, req.user.email);
558
559
  const requestedChatId = typeof body.chatId === "string" ? body.chatId.trim() : "";
@@ -593,6 +594,7 @@ function api(server, options) {
593
594
  chatId,
594
595
  user: req.user.email,
595
596
  executionMode,
597
+ activeDocId,
596
598
  loadCollection: (collectionId) => getCollectionSchema(req, collectionId),
597
599
  loadAllCollections: async () => (await options.getRenderer(req)).getCollections()
598
600
  });