{
  "version": 3,
  "sources": ["../../src/app/ai/agents/evals2/scenarios/cms/addMarkdownArticle.eval.ts"],
  "sourcesContent": ["import type { CollectionItemNode, CollectionNode } from \"document/models/CanvasTree/index.ts\"\nimport type { CollectionVariableDefinition } from \"document/models/CanvasTree/traits/CollectionVariableDefinition.ts\"\nimport { isVariableDefinition } from \"document/models/CanvasTree/traits/WithVariables.ts\"\nimport { ControlType } from \"library/index.ts\"\nimport type { Node as ProseMirrorNode } from \"prosemirror-model\"\nimport { cmsSchemaParams, makeSchema } from \"prosemirror/schema/index.ts\"\nimport { MarkName, NodeName } from \"prosemirror/schema/names.ts\"\nimport { parseRichText } from \"prosemirror/serialization/dom.ts\"\nimport { isObject, isString } from \"utils/typeChecks.ts\"\nimport { agentEvalAsset } from \"../../harness/asset.ts\"\nimport { createEvalExportZipFixture } from \"../../harness/fixture.ts\"\nimport { findCollectionByName, getCollectionItems } from \"./cmsEvalUtils.ts\"\n\nconst addMarkdownArticleRequestId = \"sIz4ZvsTo\"\nconst markdownFileName = \"in-defense-of-the-boring-meeting.md\"\nconst expectedTitle = \"In Defense of the Boring Meeting\"\nconst expectedSlug = \"in-defense-of-the-boring-meeting\"\n// Section headings authored in the attached markdown \u2014 used to confirm the agent preserves\n// h2 structure when converting Markdown to rich text rather than flattening to paragraphs.\nconst expectedHeadings: readonly string[] = [\"What async is good at\", \"What async is bad at\"]\n\nconst cmsSchema = makeSchema(cmsSchemaParams)\n\nfunction getNewArticleItem(articles: CollectionNode | undefined): CollectionItemNode | undefined {\n\tconst titleVariable = articles?.getTitleVariable()\n\tif (!articles || !titleVariable) return undefined\n\treturn getCollectionItems(articles).find(item => {\n\t\tconst value = item.getControlProp(titleVariable.id)?.value\n\t\treturn isString(value) && value.trim() === expectedTitle\n\t})\n}\n\nfunction findRichTextVariable(\n\tarticles: CollectionNode | undefined,\n): (CollectionVariableDefinition & { type: ControlType.RichText }) | undefined {\n\tif (!articles) return undefined\n\treturn articles.variables.find(\n\t\t(variable): variable is CollectionVariableDefinition & { type: ControlType.RichText } =>\n\t\t\tisVariableDefinition(variable) && variable.type === ControlType.RichText,\n\t)\n}\n\nfunction getRichTextContent(\n\titem: CollectionItemNode | undefined,\n\trichTextVariableId: string | undefined,\n): string | undefined {\n\tif (!item || richTextVariableId === undefined) return undefined\n\tconst prop = item.getControlProp(richTextVariableId)\n\tif (prop?.type !== ControlType.RichText || !isString(prop.value)) return undefined\n\treturn prop.value\n}\n\nfunction parseArticleRichText(html: string | undefined): ProseMirrorNode | undefined {\n\tif (html === undefined) return undefined\n\treturn parseRichText(html, cmsSchema)\n}\n\nfunction getBlockTags(doc: ProseMirrorNode | undefined): string[] {\n\tif (!doc) return []\n\tconst tags: string[] = []\n\tdoc.descendants(child => {\n\t\tif (child.type.name !== NodeName.TextBlock) return\n\t\tconst tag = isObject(child.attrs) && isString(child.attrs.tag) ? child.attrs.tag : undefined\n\t\tif (tag !== undefined) tags.push(tag)\n\t})\n\treturn tags\n}\n\nfunction getHeadingTexts(doc: ProseMirrorNode | undefined): string[] {\n\tif (!doc) return []\n\tconst headings: string[] = []\n\tdoc.descendants(child => {\n\t\tif (child.type.name !== NodeName.TextBlock) return\n\t\tconst tag = isObject(child.attrs) && isString(child.attrs.tag) ? child.attrs.tag : undefined\n\t\tif (tag === undefined || !/^h[1-6]$/u.test(tag)) return\n\t\tconst text = child.textContent.trim()\n\t\tif (text.length > 0) headings.push(text)\n\t})\n\treturn headings\n}\n\nfunction hasMarkAnywhere(doc: ProseMirrorNode | undefined, markName: MarkName): boolean {\n\tif (!doc) return false\n\tlet found = false\n\tdoc.descendants(child => {\n\t\tif (found) return false\n\t\tif (!child.isText) return\n\t\tif (child.marks.some(mark => mark.type.name === markName)) found = true\n\t\treturn !found\n\t})\n\treturn found\n}\n\nevaluation(\n\t\"CMS: Add Markdown Article To Collection\",\n\t// Browser-only: relies on `api.files.readText` which fetches the attachment over HTTP. In CLI/Jest\n\t// the in-process script bridge collides with Node undici's globalThis lookups during the sandbox\n\t// hardening window. The live worker path is unaffected.\n\tcreateEvalExportZipFixture(\"cms-add-markdown-article-export\", agentEvalAsset(\"./add-markdown-article-export.zip\"), {\n\t\truntimeTarget: \"browser\",\n\t}),\n\t{\n\t\tid: \"cms-add-markdown-article\",\n\t\trequestId: addMarkdownArticleRequestId,\n\t\tstepIndex: 0,\n\t\tmaxSteps: 6,\n\t},\n\t({ agent, engine, report, tools }) => {\n\t\tconst request = agent.chatMessages.at(-1)\n\t\tconst articles = findCollectionByName(engine, \"Articles\")\n\t\tconst newItem = getNewArticleItem(articles)\n\t\tconst slugVariable = articles?.getSlugVariable()\n\t\tconst richTextVariable = findRichTextVariable(articles)\n\t\tconst slugValue = newItem && slugVariable ? newItem.getControlProp(slugVariable.id)?.value : undefined\n\t\tconst richTextHtml = getRichTextContent(newItem, richTextVariable?.id)\n\t\tconst richTextDoc = parseArticleRichText(richTextHtml)\n\n\t\treport.correctness.required(\"continues captured markdown-attachment request\", () => {\n\t\t\texpect(request?.id).toBe(addMarkdownArticleRequestId)\n\t\t\texpect(request?.parts).toEqual([{ type: \"fileAttachment\", fileName: markdownFileName }, \" add this article\"])\n\t\t\texpect(request?.files?.[0]?.fileName).toBe(markdownFileName)\n\t\t})\n\n\t\treport.correctness.forbidden(\"does not produce command errors\", () => {\n\t\t\texpect(tools.commandErrors()).toHaveLength(0)\n\t\t})\n\n\t\treport.correctness.required(\"adds an Articles item with the markdown title\", () => {\n\t\t\texpect(articles).toBeDefined()\n\t\t\texpect(newItem).toBeDefined()\n\t\t})\n\n\t\treport.correctness.scored(\"sets the slug to the kebab-case of the title\", () => {\n\t\t\texpect(slugVariable).toBeDefined()\n\t\t\texpect(slugValue).toBe(expectedSlug)\n\t\t})\n\n\t\treport.correctness.scored(\"populates a non-empty rich text content field\", () => {\n\t\t\texpect(richTextHtml).toBeDefined()\n\t\t\texpect(richTextDoc?.textContent.trim().length ?? 0).toBeGreaterThan(0)\n\t\t})\n\n\t\treport.accuracy.scored(\"preserves paragraph and heading structure from markdown\", () => {\n\t\t\tconst tags = getBlockTags(richTextDoc)\n\t\t\texpect(tags.filter(tag => tag === \"p\").length).toBeGreaterThan(0)\n\t\t\texpect(tags.filter(tag => /^h[1-6]$/u.test(tag)).length).toBeGreaterThanOrEqual(2)\n\t\t})\n\n\t\treport.accuracy.each(\"preserves expected section headings\", expectedHeadings, heading => {\n\t\t\tconst headings = getHeadingTexts(richTextDoc)\n\t\t\texpect(headings).toContain(heading)\n\t\t})\n\n\t\treport.accuracy.scored(\"preserves bold or italic emphasis from markdown\", () => {\n\t\t\tconst hasBold = hasMarkAnywhere(richTextDoc, MarkName.Bold)\n\t\t\tconst hasItalic = hasMarkAnywhere(richTextDoc, MarkName.Italic)\n\t\t\texpect(hasBold || hasItalic).toBe(true)\n\t\t})\n\n\t\treport.efficiency.scored(\"reads the markdown file with a script\", () => {\n\t\t\tconst scripts = tools.scriptInputs()\n\t\t\texpect(scripts.length).toBeGreaterThan(0)\n\t\t\tconst referencesFile = scripts.some(\n\t\t\t\tscript => script.includes(\"api.files.readText\") || script.includes(markdownFileName),\n\t\t\t)\n\t\t\texpect(referencesFile).toBe(true)\n\t\t})\n\n\t\treport.efficiency.diagnostic(\"does not ask for clarification\", () => {\n\t\t\texpect(tools.clarificationQuestions()).toHaveLength(0)\n\t\t})\n\t},\n)\n"],
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAM,8BAA8B;AACpC,IAAM,mBAAmB;AACzB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AAGrB,IAAM,mBAAsC,CAAC,yBAAyB,sBAAsB;AAE5F,IAAM,YAAY,WAAW,eAAe;AAE5C,SAAS,kBAAkB,UAAsE;AAChG,QAAM,gBAAgB,UAAU,iBAAiB;AACjD,MAAI,CAAC,YAAY,CAAC,cAAe,QAAO;AACxC,SAAO,mBAAmB,QAAQ,EAAE,KAAK,UAAQ;AAChD,UAAM,QAAQ,KAAK,eAAe,cAAc,EAAE,GAAG;AACrD,WAAO,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,EAC5C,CAAC;AACF;AAEA,SAAS,qBACR,UAC8E;AAC9E,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,SAAS,UAAU;AAAA,IACzB,CAAC,aACA,qBAAqB,QAAQ,KAAK,SAAS;AAAA,EAC7C;AACD;AAEA,SAAS,mBACR,MACA,oBACqB;AACrB,MAAI,CAAC,QAAQ,uBAAuB,OAAW,QAAO;AACtD,QAAM,OAAO,KAAK,eAAe,kBAAkB;AACnD,MAAI,MAAM,sCAAiC,CAAC,SAAS,KAAK,KAAK,EAAG,QAAO;AACzE,SAAO,KAAK;AACb;AAEA,SAAS,qBAAqB,MAAuD;AACpF,MAAI,SAAS,OAAW,QAAO;AAC/B,SAAO,cAAc,MAAM,SAAS;AACrC;AAEA,SAAS,aAAa,KAA4C;AACjE,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,QAAM,OAAiB,CAAC;AACxB,MAAI,YAAY,WAAS;AACxB,QAAI,MAAM,KAAK,qCAA6B;AAC5C,UAAM,MAAM,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM;AACnF,QAAI,QAAQ,OAAW,MAAK,KAAK,GAAG;AAAA,EACrC,CAAC;AACD,SAAO;AACR;AAEA,SAAS,gBAAgB,KAA4C;AACpE,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,QAAM,WAAqB,CAAC;AAC5B,MAAI,YAAY,WAAS;AACxB,QAAI,MAAM,KAAK,qCAA6B;AAC5C,UAAM,MAAM,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,MAAM;AACnF,QAAI,QAAQ,UAAa,CAAC,YAAY,KAAK,GAAG,EAAG;AACjD,UAAM,OAAO,MAAM,YAAY,KAAK;AACpC,QAAI,KAAK,SAAS,EAAG,UAAS,KAAK,IAAI;AAAA,EACxC,CAAC;AACD,SAAO;AACR;AAEA,SAAS,gBAAgB,KAAkC,UAA6B;AACvF,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,QAAQ;AACZ,MAAI,YAAY,WAAS;AACxB,QAAI,MAAO,QAAO;AAClB,QAAI,CAAC,MAAM,OAAQ;AACnB,QAAI,MAAM,MAAM,KAAK,UAAQ,KAAK,KAAK,SAAS,QAAQ,EAAG,SAAQ;AACnE,WAAO,CAAC;AAAA,EACT,CAAC;AACD,SAAO;AACR;AAEA;AAAA,EACC;AAAA;AAAA;AAAA;AAAA,EAIA,2BAA2B,mCAAmC,eAAe,mCAAmC,GAAG;AAAA,IAClH,eAAe;AAAA,EAChB,CAAC;AAAA,EACD;AAAA,IACC,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,EACX;AAAA,EACA,CAAC,EAAE,OAAO,QAAQ,QAAQ,MAAM,MAAM;AACrC,UAAM,UAAU,MAAM,aAAa,GAAG,EAAE;AACxC,UAAM,WAAW,qBAAqB,QAAQ,UAAU;AACxD,UAAM,UAAU,kBAAkB,QAAQ;AAC1C,UAAM,eAAe,UAAU,gBAAgB;AAC/C,UAAM,mBAAmB,qBAAqB,QAAQ;AACtD,UAAM,YAAY,WAAW,eAAe,QAAQ,eAAe,aAAa,EAAE,GAAG,QAAQ;AAC7F,UAAM,eAAe,mBAAmB,SAAS,kBAAkB,EAAE;AACrE,UAAM,cAAc,qBAAqB,YAAY;AAErD,WAAO,YAAY,SAAS,kDAAkD,MAAM;AACnF,aAAO,SAAS,EAAE,EAAE,KAAK,2BAA2B;AACpD,aAAO,SAAS,KAAK,EAAE,QAAQ,CAAC,EAAE,MAAM,kBAAkB,UAAU,iBAAiB,GAAG,mBAAmB,CAAC;AAC5G,aAAO,SAAS,QAAQ,CAAC,GAAG,QAAQ,EAAE,KAAK,gBAAgB;AAAA,IAC5D,CAAC;AAED,WAAO,YAAY,UAAU,mCAAmC,MAAM;AACrE,aAAO,MAAM,cAAc,CAAC,EAAE,aAAa,CAAC;AAAA,IAC7C,CAAC;AAED,WAAO,YAAY,SAAS,iDAAiD,MAAM;AAClF,aAAO,QAAQ,EAAE,YAAY;AAC7B,aAAO,OAAO,EAAE,YAAY;AAAA,IAC7B,CAAC;AAED,WAAO,YAAY,OAAO,gDAAgD,MAAM;AAC/E,aAAO,YAAY,EAAE,YAAY;AACjC,aAAO,SAAS,EAAE,KAAK,YAAY;AAAA,IACpC,CAAC;AAED,WAAO,YAAY,OAAO,iDAAiD,MAAM;AAChF,aAAO,YAAY,EAAE,YAAY;AACjC,aAAO,aAAa,YAAY,KAAK,EAAE,UAAU,CAAC,EAAE,gBAAgB,CAAC;AAAA,IACtE,CAAC;AAED,WAAO,SAAS,OAAO,2DAA2D,MAAM;AACvF,YAAM,OAAO,aAAa,WAAW;AACrC,aAAO,KAAK,OAAO,SAAO,QAAQ,GAAG,EAAE,MAAM,EAAE,gBAAgB,CAAC;AAChE,aAAO,KAAK,OAAO,SAAO,YAAY,KAAK,GAAG,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC;AAAA,IAClF,CAAC;AAED,WAAO,SAAS,KAAK,uCAAuC,kBAAkB,aAAW;AACxF,YAAM,WAAW,gBAAgB,WAAW;AAC5C,aAAO,QAAQ,EAAE,UAAU,OAAO;AAAA,IACnC,CAAC;AAED,WAAO,SAAS,OAAO,mDAAmD,MAAM;AAC/E,YAAM,UAAU,gBAAgB,8BAA0B;AAC1D,YAAM,YAAY,gBAAgB,kCAA4B;AAC9D,aAAO,WAAW,SAAS,EAAE,KAAK,IAAI;AAAA,IACvC,CAAC;AAED,WAAO,WAAW,OAAO,yCAAyC,MAAM;AACvE,YAAM,UAAU,MAAM,aAAa;AACnC,aAAO,QAAQ,MAAM,EAAE,gBAAgB,CAAC;AACxC,YAAM,iBAAiB,QAAQ;AAAA,QAC9B,YAAU,OAAO,SAAS,oBAAoB,KAAK,OAAO,SAAS,gBAAgB;AAAA,MACpF;AACA,aAAO,cAAc,EAAE,KAAK,IAAI;AAAA,IACjC,CAAC;AAED,WAAO,WAAW,WAAW,kCAAkC,MAAM;AACpE,aAAO,MAAM,uBAAuB,CAAC,EAAE,aAAa,CAAC;AAAA,IACtD,CAAC;AAAA,EACF;AACD;",
  "names": []
}
