@bendyline/docblocks-cli 2.2.0 → 2.2.2

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/bin.js CHANGED
@@ -1872,6 +1872,66 @@ async function validatePreparedDocument(_documents, prepared, targetFormat, sign
1872
1872
  diagnostics: unique
1873
1873
  };
1874
1874
  }
1875
+ function annotationSyntaxDiagnostics(markdown, stage, format) {
1876
+ const diagnostics = [];
1877
+ const lines = markdown.split(/\r?\n/);
1878
+ let inFence = false;
1879
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
1880
+ if (diagnostics.length >= MCP_WIRE_LIMITS5.arrayEntries) break;
1881
+ const rawLine = lines[lineIndex];
1882
+ if (/^\s*(?:```|~~~)/u.test(rawLine)) {
1883
+ inFence = !inFence;
1884
+ continue;
1885
+ }
1886
+ if (inFence) continue;
1887
+ const line = rawLine.replace(/`[^`]*`/gu, "``");
1888
+ let search = 0;
1889
+ while (search < line.length) {
1890
+ const open6 = line.indexOf("{[", search);
1891
+ if (open6 === -1) break;
1892
+ const close = line.indexOf("]}", open6 + 2);
1893
+ if (close === -1) {
1894
+ diagnostics.push(
1895
+ malformedAnnotationDiagnostic(
1896
+ stage,
1897
+ format,
1898
+ lineIndex + 1,
1899
+ open6 + 1,
1900
+ 'An annotation opened with "{[" has no matching "]}" on the same line.'
1901
+ )
1902
+ );
1903
+ break;
1904
+ }
1905
+ const inner = line.slice(open6 + 2, close).replace(/"[^"]*"/gu, '""');
1906
+ if (/[{}[\]]/u.test(inner)) {
1907
+ diagnostics.push(
1908
+ malformedAnnotationDiagnostic(
1909
+ stage,
1910
+ format,
1911
+ lineIndex + 1,
1912
+ open6 + 1,
1913
+ "An annotation contains a stray brace or bracket outside quoted values."
1914
+ )
1915
+ );
1916
+ }
1917
+ search = close + 2;
1918
+ }
1919
+ }
1920
+ return diagnostics;
1921
+ }
1922
+ function malformedAnnotationDiagnostic(stage, format, line, column, message) {
1923
+ return {
1924
+ code: "malformed-template-annotation",
1925
+ severity: "warning",
1926
+ stage,
1927
+ format,
1928
+ count: 1,
1929
+ message,
1930
+ remediation: 'Repair the annotation so it reads exactly `{[templateId key="value"]}` with no extra braces or brackets, then validate again.',
1931
+ retryable: false,
1932
+ location: { kind: "source", line, column }
1933
+ };
1934
+ }
1875
1935
  async function authoringDiagnostics(prepared, stage, format, signal) {
1876
1936
  throwIfAborted5(signal);
1877
1937
  const {
@@ -1885,7 +1945,11 @@ async function authoringDiagnostics(prepared, stage, format, signal) {
1885
1945
  const blocks = flattenBlocks(prepared.doc.blocks);
1886
1946
  const analyzedBlocks = blocks.slice(0, MCP_WIRE_LIMITS5.arrayEntries);
1887
1947
  const theme = resolveThemeForDoc(prepared.doc);
1888
- const diagnostics = [];
1948
+ const diagnostics = annotationSyntaxDiagnostics(
1949
+ prepared.markdown,
1950
+ stage,
1951
+ format
1952
+ );
1889
1953
  for (let index = 0; index < analyzedBlocks.length; index += 1) {
1890
1954
  const checkpoint = cancellationCheckpoint(signal, index);
1891
1955
  if (checkpoint) await checkpoint;
@@ -4189,7 +4253,7 @@ function registerAgenticTools(server, context) {
4189
4253
  server.registerTool(
4190
4254
  "list_roots",
4191
4255
  {
4192
- description: "List opaque root aliases granted when this DocBlocks MCP server started. Root aliases improve path usability but never expand authority.",
4256
+ description: "Call first when durable local output is requested. Lists opaque startup-granted roots; if none is write-enabled, save_artifact cannot publish a file and the MCP server must be restarted with --allow-write.",
4193
4257
  inputSchema: z.object({}).strict(),
4194
4258
  outputSchema: DOCBLOCKS_MCP_TOOL_OUTPUT_SCHEMAS.list_roots,
4195
4259
  annotations: READ_ONLY
@@ -4197,7 +4261,7 @@ function registerAgenticTools(server, context) {
4197
4261
  async () => {
4198
4262
  try {
4199
4263
  const roots = (await context.authority).listRoots();
4200
- return textAndStructured({ roots });
4264
+ return textAndStructured({ roots }, rootDiscoveryText(roots));
4201
4265
  } catch (caught) {
4202
4266
  return errorResult(caught, "resolve");
4203
4267
  }
@@ -4274,7 +4338,7 @@ function registerAgenticTools(server, context) {
4274
4338
  server.registerTool(
4275
4339
  "create_document_bundle",
4276
4340
  {
4277
- description: "Optionally stage Markdown plus authority-scoped assets as a reusable immutable DBK artifact when the same bundle will feed several operations. For normal authoring, pass complete Markdown or a bundle source directly to convert_document.",
4341
+ description: "Stage Markdown plus authority-scoped assets as a reusable immutable DBK artifact when the same complete draft will be passed to two or more validate, inspect, preview, or convert calls. Pass its artifact URI instead of repeating the Markdown.",
4278
4342
  inputSchema: z.object({ source: bundleDocumentSourceSchema }).strict(),
4279
4343
  outputSchema: DOCBLOCKS_MCP_TOOL_OUTPUT_SCHEMAS.create_document_bundle,
4280
4344
  annotations: ARTIFACT_CREATING
@@ -4348,7 +4412,7 @@ function registerAgenticTools(server, context) {
4348
4412
  server.registerTool(
4349
4413
  "inspect_document",
4350
4414
  {
4351
- description: "Inspect any linked-registry document as bounded semantic structure, block provenance, assets, metadata, theme, and diagnostics.",
4415
+ description: "Inspect bounded semantic structure, block provenance, assets, metadata, theme, and diagnostics. Use for those details; do not pair it with validate_document for a routine export preflight.",
4352
4416
  inputSchema: z.object({
4353
4417
  source: documentSourceSchema,
4354
4418
  maxBlocks: z.number().int().min(1).max(2e3).optional(),
@@ -4380,7 +4444,7 @@ function registerAgenticTools(server, context) {
4380
4444
  server.registerTool(
4381
4445
  "validate_document",
4382
4446
  {
4383
- description: "Validate document structure, templates, annotations, assets, accessibility, and optional target-format fidelity before export.",
4447
+ description: "Primary pre-export review for structure, template content retention, annotations, assets, accessibility, and target fidelity. Diagnostics include repairs; normally do not also call inspect_document.",
4384
4448
  inputSchema: z.object({
4385
4449
  source: documentSourceSchema,
4386
4450
  targetFormat: formatInputSchema.nullable().optional()
@@ -4553,7 +4617,7 @@ function registerAuthoringGuideResource(server) {
4553
4617
  "authoring-guide",
4554
4618
  "docblocks://authoring-guide",
4555
4619
  {
4556
- description: "Compact linked-Squisq authoring vocabulary, artifact workflow, fidelity modes, templates, themes, and transform styles.",
4620
+ description: "Complete linked-Squisq authoring catalog with exact template inputs, fidelity modes, themes, and transform styles. Read only when the focused authoring context is insufficient.",
4557
4621
  mimeType: "application/json",
4558
4622
  annotations: { audience: ["assistant"], priority: 1 }
4559
4623
  },
@@ -4564,15 +4628,15 @@ function registerAuthoringGuideResource(server) {
4564
4628
  import("@bendyline/squisq/transform")
4565
4629
  ]);
4566
4630
  const guide = {
4567
- version: 6,
4631
+ version: 7,
4568
4632
  workflow: [
4569
4633
  "treat supplied facts as a closed evidence set; label calculations, assumptions, hypotheses, recommendations, and examples; do not present causal links, rhetorical performance labels, superlatives, sole causes, targets, capabilities, owners, dates, channels, or operational details as established facts unless supplied",
4570
4634
  "when the requested genre needs unsupplied roles, gates, timelines, channels, or procedures, add one explicit proposed operating model scope note that applies to those details, then complete the requested element",
4571
4635
  "author complete Squisq-compatible Markdown with annotations bound to headings; ordinary headings default to the loss-averse content template",
4572
4636
  "for PPTX, use exactly one level-one Markdown heading per slide and no level-two through level-six headings because every heading becomes a slide by default",
4573
4637
  "by default, pass the complete Markdown\u2014or a bundle source when assets are needed\u2014directly to convert_document; revise by editing the complete Markdown and converting again",
4574
- "use create_document_bundle only when a reusable staged DBK materially avoids repeating a large Markdown-and-asset bundle across several operations",
4575
- "use inspect_document, validate_document, and preview_document when their semantic, diagnostic, or visual evidence is useful; they are review tools rather than required phases",
4638
+ "use create_document_bundle when the same complete draft will be passed to two or more validate, inspect, preview, or convert calls, then pass its artifact URI instead of repeating Markdown",
4639
+ "use validate_document as the routine export preflight; use inspect_document only for semantic structure, provenance, assets, metadata, or theme details; use preview_document only when visual evidence is useful",
4576
4640
  "for visual polish, replace selected content blocks with compatible visual templates while preserving required content",
4577
4641
  "convert_document creates one or more immutable artifacts from the authoritative complete source",
4578
4642
  "save_artifact only when a durable file is required"
@@ -4616,7 +4680,7 @@ function registerTemplateTools(server, context) {
4616
4680
  server.registerTool(
4617
4681
  "get_authoring_context",
4618
4682
  {
4619
- description: "Get a compact agent-facing authoring contract plus the complete linked-Squisq catalog in structured content, with optional block recommendations.",
4683
+ description: "Get a focused authoring contract, target capability, safe default template, themes, transforms, and optional source-based recommendations. Exact full template inputs remain on demand through describe_template or docblocks://authoring-guide.",
4620
4684
  inputSchema: z.object({
4621
4685
  targetFormat: formatInputSchema.optional(),
4622
4686
  goal: z.enum(["content-first", "visual-polish"]).optional(),
@@ -4639,11 +4703,13 @@ function registerTemplateTools(server, context) {
4639
4703
  throw new Error(`Format "${normalizedTarget}" is not export-capable`);
4640
4704
  }
4641
4705
  }
4642
- const [templates, schemaModule, transformModule] = await Promise.all([
4706
+ const [fullTemplates, schemaModule, transformModule] = await Promise.all([
4643
4707
  authoringTemplateCatalog(),
4644
4708
  import("@bendyline/squisq/schemas"),
4645
4709
  import("@bendyline/squisq/transform")
4646
4710
  ]);
4711
+ const annotationHandling = normalizedTarget ? await targetTemplateAnnotationHandling(normalizedTarget) : null;
4712
+ const candidateTemplates = annotationHandling === "ignored" ? fullTemplates.filter((template) => template.safeForContentFirst) : fullTemplates;
4647
4713
  let recommendations = [];
4648
4714
  let totalBlocks = null;
4649
4715
  let truncated = false;
@@ -4663,7 +4729,7 @@ function registerTemplateTools(server, context) {
4663
4729
  const profile = recommendModule.profileBlockContents(block.contents ?? []);
4664
4730
  const visual = recommendModule.recommendTemplatesForBlock(
4665
4731
  profile,
4666
- templates.map((template) => template.id)
4732
+ candidateTemplates.map((template) => template.id)
4667
4733
  ).recommended;
4668
4734
  const recommendedTemplateIds = goal === "content-first" ? ["content", ...visual.filter((id) => id !== "content")] : visual;
4669
4735
  return {
@@ -4687,29 +4753,23 @@ function registerTemplateTools(server, context) {
4687
4753
  defaultTemplateId: "content",
4688
4754
  defaultFidelity: authoringDefaultFidelity(normalizedTarget, goal),
4689
4755
  workflow: [
4690
- "Treat supplied facts as a closed evidence set. Use temporal or correlational wording unless causality is supplied. Label calculations, assumptions, hypotheses, recommendations, and illustrative examples. Do not infer end-to-end feasibility from one supplied phase duration.",
4691
- "Audit claims before conversion: causal links, rhetorical labels such as compounding, engine, healthy, strong, or constraint, superlatives, sole-cause claims, targets, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed as a hypothesis, recommendation, example, or proposal. Do not connect separate metrics, audiences, segments, or workflows unless the relationship is supplied. Prefer observed, coincided with, intended to, or proposed over drove, addresses, protects, or proves. Do not call choices a sequence or capacity allocation unless order, timing, or resource constraints were supplied.",
4692
- "Complete every requested element without presenting invented policy as established fact. When a requested policy, playbook, or training guide needs unsupplied roles, gates, timelines, channels, or procedures, add one explicit proposed operating model scope note placed before the first such detail so it governs all of them.",
4693
- "Generic option traits\u2014control, flexibility, vendor support, freed capacity, switching costs\u2014are capability claims: state one only when supplied or labeled Assumption or Judgment, even in table cells and tradeoffs.",
4694
- "Author complete Squisq-compatible content with heading-bound annotations; ordinary headings default to the loss-averse content template.",
4756
+ "For durable local output, call list_roots before drafting. If no returned root is write-enabled, stop and explain that the MCP server must restart with --allow-write; do not fall back to a shell or CLI converter. A transient artifact is acceptable only when the user did not require a file.",
4757
+ "Treat supplied facts as a closed evidence set. Preserve them exactly; label calculations, assumptions, hypotheses, recommendations, causal claims, capabilities, owners, dates, and unsupplied operating details. When a requested policy or playbook needs invented procedures, introduce one proposed operating model scope note before those details.",
4695
4758
  normalizedTarget === "pptx" ? "Match every explicitly requested slide count exactly. Use exactly one level-one Markdown heading (#) per slide and no level-two through level-six headings because every heading becomes a slide by default. Target at most 80 words per slide, and use lists, tables, or bold labels for within-slide structure." : "Honor the requested word range and document genre. Prefer connected memo prose for executive decisions and native headings, tables, and checklists for operational documents.",
4696
- normalizedTarget === "pptx" ? "Make slide one a supported point-of-view thesis, not a generic title or unsupported flourish. For requested choices, state a concrete opportunity cost grounded in the supplied alternatives and name one clearly labeled proposed accountable role per choice. If a tradeoff requires an unsupplied capacity or outcome assumption, label it Assumption or Potential tradeoff rather than stating it as fact." : "Tie each decision implication or comparative judgment to a supplied fact or calculation, or label it Judgment. When accountability is requested but not supplied, name one clearly labeled proposed accountable role per decision or workstream.",
4697
- "Add decision value without inventing causes: interpret supplied comparisons to baselines, goals, targets, and rankings; use transparent calculations; label any new review cadence or measurement procedure as proposed.",
4698
- "Before validation and conversion, run a content preflight: count slide sections or document words, verify every requested element, and rewrite or label every unsupported claim.",
4699
- "Use the complete Markdown as the authoritative source. Pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document, and revise by editing the complete Markdown and converting again.",
4700
- "Use create_document_bundle only when reusing a large Markdown-and-asset bundle across several review or conversion operations would materially reduce retransmission.",
4701
- "Use inspect_document or validate_document when semantic structure, content retention, accessibility, or target diagnostics need review; repair actionable findings in the authoritative Markdown.",
4702
- "Use preview_document when visual evidence is needed, inspect previewBasis, and repair overflow or layout problems in the authoritative Markdown.",
4703
- normalizedTarget === "pptx" ? "For visual polish, replace selected content blocks with compatible recommended templates; use patterns such as definitionCard for a definition, dataTable for a true table, comparisonBar for supported numeric comparisons, and list for concise steps when the returned catalog supports them. Preserve all required content and preview again." : "For visual polish, use native headings, tables, and checklists where they improve scanning; keep complete-body content when a visual template would discard detail, then preview again.",
4704
- "Convert to immutable artifacts, inspect conversion reports, and save only final durable outputs."
4759
+ "Author the complete Squisq-compatible Markdown with annotations bound to headings. Ordinary headings default to the loss-averse content template; keep that default until the complete content is sound.",
4760
+ "Before conversion, count slide sections or document words, verify every requested element, and rewrite or label unsupported claims. For decisions, ground tradeoffs in supplied alternatives and label unsupplied accountability, capacity, outcomes, and review cadences as proposed or assumed.",
4761
+ "Use validate_document as the routine export preflight and follow its repair diagnostics. Call inspect_document only when semantic structure, provenance, assets, metadata, or theme details are needed.",
4762
+ "When the same complete draft will feed two or more validate, inspect, preview, or convert calls, stage it once with create_document_bundle and reuse its artifact URI; after edits, stage the revised draft again.",
4763
+ normalizedTarget === "pptx" ? "For visual polish, call recommend_templates on the complete draft, then describe_template only for selected candidates before replacing content blocks. Preserve required content and use preview_document only when visual evidence is needed." : annotationHandling === "ignored" ? "This target flattens template annotations to semantic content, so visual templates have no effect on the exported file: rely on native headings, tables, and checklists for structure and scanning." : "For visual polish, use native headings, tables, and checklists where they improve scanning; describe a selected visual template before use and keep complete-body content when it would discard detail.",
4764
+ "Pass the authoritative Markdown or bundle source directly to convert_document. It returns immutable artifacts; call save_artifact only for final durable outputs and never switch to a shell or CLI converter."
4705
4765
  ],
4706
4766
  syntax: {
4707
4767
  headingAnnotation: "# Heading {[content]}",
4708
4768
  standaloneAnnotation: "{[content]}",
4709
4769
  standaloneWarning: "A standalone annotation creates an additional heading-less block. Bind it to a heading unless that extra block is deliberate."
4710
4770
  },
4711
- formats,
4712
- templates,
4771
+ formats: normalizedTarget ? formats.filter((format) => format.id === normalizedTarget) : formats,
4772
+ templates: focusedAuthoringTemplates(candidateTemplates, recommendations),
4713
4773
  themes: schemaModule.getThemeSummaries().slice(0, MCP_WIRE_LIMITS7.arrayEntries).map((theme) => ({
4714
4774
  id: requireWireIdentifier(theme.id, "theme id"),
4715
4775
  name: boundWireText(theme.name, MCP_WIRE_LIMITS7.labelCharacters, theme.id),
@@ -4724,7 +4784,19 @@ function registerTemplateTools(server, context) {
4724
4784
  totalBlocks,
4725
4785
  truncated
4726
4786
  };
4727
- return textAndStructured(payload, compactAuthoringContextText(payload));
4787
+ return {
4788
+ content: [
4789
+ { type: "text", text: compactAuthoringContextText(payload) },
4790
+ {
4791
+ type: "resource_link",
4792
+ uri: "docblocks://authoring-guide",
4793
+ name: "authoring-guide",
4794
+ description: "Complete linked-Squisq authoring catalog; read only if needed.",
4795
+ mimeType: "application/json"
4796
+ }
4797
+ ],
4798
+ structuredContent: asStructuredContent(successResult(payload))
4799
+ };
4728
4800
  });
4729
4801
  } catch (caught) {
4730
4802
  return errorResult(caught, "inspect", null, extra.signal);
@@ -5140,6 +5212,25 @@ function textAndStructured(payload, text = JSON.stringify(payload, null, 2)) {
5140
5212
  structuredContent: asStructuredContent(successResult(payload))
5141
5213
  };
5142
5214
  }
5215
+ function rootDiscoveryText(roots) {
5216
+ if (roots.length === 0) {
5217
+ return "No DocBlocks MCP roots are configured. Durable file output is unavailable: restart the server with --allow-write <directory>. Do not fall back to a shell or CLI converter; keep a transient artifact only when the user did not require a file.";
5218
+ }
5219
+ const catalog = JSON.stringify({ roots }, null, 2);
5220
+ if (roots.some((root) => root.write)) return catalog;
5221
+ return `${catalog}
5222
+
5223
+ No returned root is write-enabled. Durable file output is unavailable: restart the server with --allow-write <directory>. Do not fall back to a shell or CLI converter.`;
5224
+ }
5225
+ function focusedAuthoringTemplates(candidates, recommendations) {
5226
+ const selectedIds = /* @__PURE__ */ new Set(["content"]);
5227
+ for (const recommendation of recommendations) {
5228
+ for (const templateId of recommendation.recommendedTemplateIds) {
5229
+ selectedIds.add(templateId);
5230
+ }
5231
+ }
5232
+ return candidates.filter((template) => selectedIds.has(template.id));
5233
+ }
5143
5234
  function compactAuthoringContextText(context) {
5144
5235
  const target = context.targetFormat ?? "unspecified target";
5145
5236
  const lines = [
@@ -5153,7 +5244,7 @@ function compactAuthoringContextText(context) {
5153
5244
  `Warning: ${context.syntax.standaloneWarning}`,
5154
5245
  `Templates (${context.templates.length}): ${context.templates.map(({ id }) => id).join(", ")}`,
5155
5246
  `Themes (${context.themes.length}): ${context.themes.map(({ id }) => id).join(", ")}`,
5156
- `Transform styles (${context.transformStyles.length}): ${context.transformStyles.map(({ id }) => id).join(", ")}`
5247
+ `Transform styles (${context.transformStyles.length}): ${context.transformStyles.map(({ id }) => id).join(", ")} \u2014 transforms re-compose blocks and can change section count; avoid on exact-count briefs.`
5157
5248
  ];
5158
5249
  if (context.recommendations.length > 0) {
5159
5250
  lines.push(
@@ -5164,7 +5255,7 @@ function compactAuthoringContextText(context) {
5164
5255
  }
5165
5256
  lines.push(
5166
5257
  "",
5167
- "The complete exact format, template-input, theme, transform, and recommendation catalog is in structuredContent. Use describe_template for focused follow-up when structured content is unavailable."
5258
+ "This response is intentionally focused. Use recommend_templates on a complete draft, describe_template for exact selected inputs, or read docblocks://authoring-guide only when the full catalog is required."
5168
5259
  );
5169
5260
  return lines.join("\n");
5170
5261
  }
@@ -5232,6 +5323,15 @@ async function authoringTemplateCatalog() {
5232
5323
  };
5233
5324
  });
5234
5325
  }
5326
+ async function targetTemplateAnnotationHandling(targetFormat) {
5327
+ const { createCliRegistry: createCliRegistry2 } = await import("@bendyline/squisq-cli/api");
5328
+ const definition = createCliRegistry2().get(targetFormat);
5329
+ if (definition && typeof definition === "object" && "templateAnnotationHandling" in definition) {
5330
+ const value = definition.templateAnnotationHandling;
5331
+ if (value === "rendered" || value === "preserved" || value === "ignored") return value;
5332
+ }
5333
+ return null;
5334
+ }
5235
5335
  function authoringDefaultFidelity(targetFormat, goal) {
5236
5336
  if (!targetFormat) return null;
5237
5337
  if (targetFormat === "mp4" || targetFormat === "gif") return "rendered-fidelity";
@@ -5633,34 +5733,37 @@ function registerAuthoringPrompts(server) {
5633
5733
  function presentationPrompt(topic, style, theme, template) {
5634
5734
  return `Create a presentation about: ${topic}
5635
5735
 
5636
- 1. Call get_authoring_context with targetFormat "pptx" and goal "content-first" for the complete linked-Squisq vocabulary and workflow in one response.
5637
- 2. Treat the topic facts as a closed evidence set. Preserve them exactly, use temporal or correlational wording unless causality is supplied, and label calculations, assumptions, hypotheses, recommendations, and examples. Causal links, rhetorical performance labels, superlatives, sole causes, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed. Do not connect separate metrics, audiences, segments, or workflows unless the relationship is supplied. Prefer observed, coincided with, intended to, or proposed over drove, addresses, protects, or proves. Add decision value through supplied baselines, goals, targets, rankings, and transparent calculations. Do not call choices a sequence or capacity allocation unless order, timing, or resources were supplied. When the requested content needs unsupplied operating details, add one proposed operating model scope note that applies to them.
5638
- 3. Match every explicitly requested slide count exactly. Use exactly one level-one Markdown heading (\`#\`) per slide and no level-two through level-six headings because every heading becomes a slide by default; use lists, tables, or bold labels within a slide. Target at most 80 words per slide. Make slide one a supported point-of-view thesis, not a generic title or unsupported flourish. For requested choices, state concrete opportunity costs grounded in supplied alternatives and one clearly labeled proposed accountable role per choice. Label any unsupplied capacity or outcome assumption as \`Assumption:\` or \`Potential tradeoff:\`. Author complete Markdown sections with accessible alt text. Put annotations on headings, for example \`# Heading {[content]}\`; a standalone \`{[template]}\` creates an extra block. Prefer style "${style ?? "choose from the returned transform styles"}", theme "${theme ?? "choose from the returned themes"}", and template "${template ?? "content until visual optimization"}".
5639
- 4. Keep the complete Markdown as the authoritative draft. Pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document. Use create_document_bundle only when the same materially large Markdown-and-asset bundle will feed several operations. Do not write a temporary local Markdown file or invent a root id.
5640
- 5. Before conversion, count slide sections, verify every requested element, and rewrite or label every unsupported claim. Label any new review cadence or measurement procedure as proposed. Use validate_document when syntax, accessibility, retention, or target diagnostics need review; use preview_document when visual evidence such as overflow needs review. Repair findings in the complete Markdown.
5641
- 6. Only after content coverage is acceptable, replace selected \`content\` blocks with compatible visual templates such as \`definitionCard\`, \`dataTable\`, \`comparisonBar\`, or \`list\` when their semantic inputs fit. Preserve required content.
5642
- 7. Call convert_document with the complete source and a pptx target. Choose editable-native for editable Office structures, rendered-fidelity for exact Squisq visuals, or hybrid for rendered visuals plus semantic retention. Revise by editing the complete Markdown and converting again.
5643
- 8. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5736
+ 1. For durable output, call list_roots before drafting. If no returned root is write-enabled, stop and explain that the MCP server must restart with --allow-write; do not use a shell or CLI converter.
5737
+ 2. Call get_authoring_context with targetFormat "pptx" and goal "content-first" for the focused linked-Squisq workflow and safe default. Read the full authoring-guide resource only if focused follow-up tools are insufficient.
5738
+ 3. Treat the topic facts as a closed evidence set. Preserve them exactly, use temporal or correlational wording unless causality is supplied, and label calculations, assumptions, hypotheses, recommendations, and examples. Causal links, rhetorical performance labels, superlatives, sole causes, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed. Do not connect separate metrics, audiences, segments, or workflows unless the relationship is supplied. Prefer observed, coincided with, intended to, or proposed over drove, addresses, protects, or proves. Add decision value through supplied baselines, goals, targets, rankings, and transparent calculations. Do not call choices a sequence or capacity allocation unless order, timing, or resources were supplied. When the requested content needs unsupplied operating details, add one proposed operating model scope note that applies to them.
5739
+ 4. Match every explicitly requested slide count exactly. Use exactly one level-one Markdown heading (\`#\`) per slide and no level-two through level-six headings because every heading becomes a slide by default; use lists, tables, or bold labels within a slide. Target at most 80 words per slide. Make slide one a supported point-of-view thesis, not a generic title or unsupported flourish. For requested choices, state concrete opportunity costs grounded in supplied alternatives and one clearly labeled proposed accountable role per choice. Label any unsupplied capacity or outcome assumption as \`Assumption:\` or \`Potential tradeoff:\`. Author complete Markdown sections with accessible alt text. Put annotations on headings, for example \`# Heading {[content]}\`; a standalone \`{[template]}\` creates an extra block. Prefer style "${style ?? "choose from the returned transform styles"}", theme "${theme ?? "choose from the returned themes"}", and template "${template ?? "content until visual optimization"}".
5740
+ 5. Keep the complete Markdown as the authoritative draft. If it will feed two or more validate, inspect, preview, or convert calls, stage it once with create_document_bundle and reuse the artifact URI. Otherwise pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document. Do not write a temporary local Markdown file or invent a root id.
5741
+ 6. Before conversion, count slide sections, verify every requested element, and rewrite or label every unsupported claim. Use validate_document as the routine export preflight; use inspect_document only for semantic or metadata detail and preview_document only for visual evidence such as overflow. Repair findings in the complete Markdown.
5742
+ 7. Only after content coverage is acceptable, call recommend_templates, describe only selected candidates, and replace compatible \`content\` blocks when their semantic inputs fit. Preserve required content.
5743
+ 8. Call convert_document with the complete source and a pptx target. Choose editable-native for editable Office structures, rendered-fidelity for exact Squisq visuals, or hybrid for rendered visuals plus semantic retention. Revise by editing the complete Markdown and converting again.
5744
+ 9. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5644
5745
  }
5645
5746
  function videoPrompt(topic, orientation, theme, template) {
5646
5747
  return `Create a video about: ${topic}
5647
5748
 
5648
- 1. Call get_authoring_context with targetFormat "mp4" for the complete linked-Squisq vocabulary and workflow.
5649
- 2. Author concise Markdown for a ${orientation ?? "landscape"} animated sequence using theme "${theme ?? "choose from the returned themes"}" and template "${template ?? "content until visual optimization"}". Bind annotations to headings.
5650
- 3. Keep the complete Markdown as the authoritative draft and pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document. Use validate_document for uncertain target constraints and preview_document when representative-frame evidence is useful; repair findings in the complete Markdown.
5651
- 4. Call convert_document with the complete source, an mp4 target, and orientation "${orientation ?? "landscape"}"; monitor progress and honor cancellation. Revise by editing the complete Markdown and converting again.
5652
- 5. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5749
+ 1. For durable output, call list_roots before drafting and stop if no root is write-enabled; do not use a shell or CLI converter.
5750
+ 2. Call get_authoring_context with targetFormat "mp4" for the focused linked-Squisq workflow.
5751
+ 3. Author concise Markdown for a ${orientation ?? "landscape"} animated sequence using theme "${theme ?? "choose from the returned themes"}" and template "${template ?? "content until visual optimization"}". Bind annotations to headings.
5752
+ 4. Keep the complete Markdown as the authoritative draft and pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document. Use validate_document for uncertain target constraints and preview_document when representative-frame evidence is useful; repair findings in the complete Markdown.
5753
+ 5. Call convert_document with the complete source, an mp4 target, and orientation "${orientation ?? "landscape"}"; monitor progress and honor cancellation. Revise by editing the complete Markdown and converting again.
5754
+ 6. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5653
5755
  }
5654
5756
  function documentPrompt(topic, format, theme, template) {
5655
5757
  const target = format ?? "pdf";
5656
5758
  return `Create a professional document about: ${topic}
5657
5759
 
5658
- 1. Call get_authoring_context with targetFormat "${target}" for the complete linked-Squisq vocabulary and workflow.
5659
- 2. Treat the topic facts as a closed evidence set. Preserve them exactly, use temporal or correlational wording unless causality is supplied, and label calculations, assumptions, hypotheses, recommendations, and examples. Causal links, superlatives, sole causes, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed. When the requested genre needs unsupplied roles, gates, timelines, channels, or procedures, add one proposed operating model scope note that applies to those details.
5660
- 3. Honor the requested word range and document genre. Author structured Markdown using theme "${theme ?? "choose from the returned themes"}" and template "${template ?? "content until visual optimization"}". Bind annotations to headings. Use connected memo prose for executive decisions and native headings, tables, and checklists for operational documents; retain complete-body content when a visual template would discard detail.
5661
- 4. Before conversion, count document words, verify every requested element, and rewrite or label every unsupported claim. Keep the complete Markdown as the authoritative draft and pass it\u2014or a bundle source when assets are needed\u2014directly to convert_document. Use validate_document when syntax, accessibility, retention, or target diagnostics need review, and preview_document when page-layout evidence is useful; repair findings in the complete Markdown.
5662
- 5. Call convert_document with the complete source and a ${target} target to create an immutable artifact. Revise by editing the complete Markdown and converting again.
5663
- 6. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5760
+ 1. For durable output, call list_roots before drafting and stop if no root is write-enabled; do not use a shell or CLI converter.
5761
+ 2. Call get_authoring_context with targetFormat "${target}" for the focused linked-Squisq workflow.
5762
+ 3. Treat the topic facts as a closed evidence set. Preserve them exactly, use temporal or correlational wording unless causality is supplied, and label calculations, assumptions, hypotheses, recommendations, and examples. Causal links, superlatives, sole causes, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed. When the requested genre needs unsupplied roles, gates, timelines, channels, or procedures, add one proposed operating model scope note that applies to those details.
5763
+ 4. Honor the requested word range and document genre. Author structured Markdown using theme "${theme ?? "choose from the returned themes"}" and template "${template ?? "content until visual optimization"}". Bind annotations to headings. Use connected memo prose for executive decisions and native headings, tables, and checklists for operational documents; retain complete-body content when a visual template would discard detail.
5764
+ 5. Before conversion, count document words, verify every requested element, and rewrite or label every unsupported claim. If the complete draft will feed two or more review or conversion calls, stage it with create_document_bundle and reuse the artifact URI. Use validate_document as the routine export preflight and preview_document only when page-layout evidence is useful; repair findings in the complete Markdown.
5765
+ 6. Call convert_document with the complete source and a ${target} target to create an immutable artifact. Revise by editing the complete Markdown and converting again.
5766
+ 7. Use get_conversion_report for provenance and save_artifact only when a durable file is required.`;
5664
5767
  }
5665
5768
  function complete(values, prefix) {
5666
5769
  const value = prefix ?? "";
@@ -5702,7 +5805,16 @@ function createMcpServer(options = {}) {
5702
5805
  const server = new McpServer(
5703
5806
  { name: "docblocks", version: getPackageVersion() },
5704
5807
  {
5705
- instructions: "Treat provided facts as a closed evidence set: preserve them exactly; use temporal or correlational wording unless causality is supplied; label calculations, assumptions, hypotheses, recommendations, and examples. Causal links, rhetorical performance labels, superlatives, sole causes, targets, capabilities, owners, dates, channels, and operational details must be supplied or explicitly framed. Do not connect separate metrics, audiences, segments, or workflows unless the relationship is supplied. Prefer observed, coincided with, intended to, or proposed over drove, addresses, protects, or proves. Add decision value through supplied baselines, goals, targets, rankings, and transparent calculations. Do not call choices a sequence or capacity allocation unless order, timing, or resources were supplied. When a requested policy, playbook, or training guide needs unsupplied operating details, add one proposed operating model scope note, then complete every requested element. Match explicit slide/page counts and word ranges exactly; target at most 80 words per presentation section. Make slide one a supported point-of-view thesis. For requested choices, state concrete opportunity costs grounded in supplied alternatives and one proposed accountable role per choice; label unsupplied capacity, outcome, or review-cadence assumptions. Before conversion, count sections or words, verify required elements, and audit unsupported claims. Start with get_authoring_context for the compact linked-Squisq contract and structured catalog. Author complete Squisq-compatible Markdown with template annotations on headings, for example `# Heading {[content]}`; standalone `{[template]}` creates an extra heading-less block. Ordinary headings default to the loss-averse `content` template. The canonical path is complete Markdown\u2014or a bundle source when assets are needed\u2014directly into convert_document; revise by editing the complete Markdown and converting again. create_document_bundle is optional for materially large, reusable Markdown-and-asset bundles. Use inspect_document, validate_document, and preview_document when their evidence is useful rather than as required phases. Save only the final durable artifact. Never invent root ids: call list_roots and use an id exactly as returned."
5808
+ instructions: [
5809
+ "For durable local output, call list_roots before drafting and use a returned write-enabled root id exactly as given. If none is writable, stop and explain that the server must restart with --allow-write; do not fall back to a shell or CLI converter.",
5810
+ "Call get_authoring_context once for the focused linked-Squisq contract. Read the full authoring-guide resource or call describe_template only when exact additional catalog detail is needed; do not also enumerate catalogs by default.",
5811
+ "Treat supplied facts as a closed evidence set: preserve them exactly, use temporal or correlational wording unless causality is supplied, and label calculations, assumptions, hypotheses, recommendations, capabilities, owners, dates, and unsupplied operating details. For a policy or playbook, introduce one proposed operating model scope note before invented procedures.",
5812
+ "Honor explicit slide/page counts and word ranges. For PPTX use one level-one heading per slide, no lower-level headings, and at most 80 words per slide. Ground decision tradeoffs in supplied alternatives and label unsupplied accountability, capacity, outcomes, or review cadences as proposed or assumed.",
5813
+ "Author complete Squisq-compatible Markdown with annotations on headings, for example `# Heading {[content]}`. Ordinary headings default to the loss-averse content template; standalone annotations create an extra heading-less block.",
5814
+ "Use validate_document as the routine export preflight and repair its diagnostics. Use inspect_document only for semantic structure, provenance, assets, metadata, or theme details, and preview_document only when visual evidence is useful.",
5815
+ "When the same complete draft will feed two or more validate, inspect, preview, or convert calls, stage it once with create_document_bundle and reuse its artifact URI instead of resending Markdown.",
5816
+ "Pass the complete Markdown or bundle source directly into convert_document. Save only the final durable artifact with save_artifact; never invent root ids or switch conversion to a shell or CLI."
5817
+ ].join(" ")
5706
5818
  }
5707
5819
  );
5708
5820
  registerAgenticTools(server, {
package/dist/eval/cli.js CHANGED
@@ -704,7 +704,8 @@ function missingArtifact(caught) {
704
704
  }
705
705
 
706
706
  // src/eval/codex-host.ts
707
- import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
707
+ import { mkdtemp, readFile as readFile3, rm, writeFile as writeFile2 } from "fs/promises";
708
+ import { tmpdir } from "os";
708
709
  import path3 from "path";
709
710
  import { z } from "zod";
710
711
 
@@ -908,17 +909,30 @@ async function runGeneration(options, testCase, caseDirectory) {
908
909
  const prompt = generationPrompt(testCase, options.profile);
909
910
  await writeFile2(path3.join(caseDirectory, "generation-prompt.txt"), prompt);
910
911
  const resolved = await resolveCodexCommand(options.codexCommand);
912
+ const agentCwd = await mkdtemp(path3.join(tmpdir(), "docblocks-eval-agent-"));
911
913
  const args = [
912
914
  ...resolved.prefixArgs,
913
- ...buildCodexGenerationArgs(options, testCase, caseDirectory, outputSchemaPath, finalPath)
915
+ ...buildCodexGenerationArgs(
916
+ options,
917
+ testCase,
918
+ caseDirectory,
919
+ agentCwd,
920
+ outputSchemaPath,
921
+ finalPath
922
+ )
914
923
  ];
915
- const capture = await runCapturedProcess({
916
- command: resolved.command,
917
- args,
918
- cwd: options.repoRoot,
919
- stdin: prompt,
920
- timeoutMs: 15 * 60 * 1e3
921
- });
924
+ let capture;
925
+ try {
926
+ capture = await runCapturedProcess({
927
+ command: resolved.command,
928
+ args,
929
+ cwd: agentCwd,
930
+ stdin: prompt,
931
+ timeoutMs: 15 * 60 * 1e3
932
+ });
933
+ } finally {
934
+ await rm(agentCwd, { recursive: true, force: true }).catch(() => void 0);
935
+ }
922
936
  await Promise.all([
923
937
  writeFile2(path3.join(caseDirectory, "generation-trace.jsonl"), capture.stdout),
924
938
  writeFile2(path3.join(caseDirectory, "generation-stderr.log"), capture.stderr)
@@ -951,6 +965,7 @@ async function runLlmJudge(options, testCase, markdown, caseDirectory) {
951
965
  const prompt = judgePrompt(testCase, markdown);
952
966
  await writeFile2(path3.join(caseDirectory, "judge-prompt.txt"), prompt);
953
967
  const resolved = await resolveCodexCommand(options.codexCommand);
968
+ const judgeCwd = await mkdtemp(path3.join(tmpdir(), "docblocks-eval-judge-"));
954
969
  const args = [
955
970
  ...resolved.prefixArgs,
956
971
  "exec",
@@ -964,7 +979,7 @@ async function runLlmJudge(options, testCase, markdown, caseDirectory) {
964
979
  "--color",
965
980
  "never",
966
981
  "--cd",
967
- caseDirectory,
982
+ judgeCwd,
968
983
  "--output-schema",
969
984
  outputSchemaPath,
970
985
  "--output-last-message",
@@ -972,13 +987,18 @@ async function runLlmJudge(options, testCase, markdown, caseDirectory) {
972
987
  ...options.model ? ["--model", options.model] : [],
973
988
  "-"
974
989
  ];
975
- const capture = await runCapturedProcess({
976
- command: resolved.command,
977
- args,
978
- cwd: options.repoRoot,
979
- stdin: prompt,
980
- timeoutMs: 10 * 60 * 1e3
981
- });
990
+ let capture;
991
+ try {
992
+ capture = await runCapturedProcess({
993
+ command: resolved.command,
994
+ args,
995
+ cwd: judgeCwd,
996
+ stdin: prompt,
997
+ timeoutMs: 10 * 60 * 1e3
998
+ });
999
+ } finally {
1000
+ await rm(judgeCwd, { recursive: true, force: true }).catch(() => void 0);
1001
+ }
982
1002
  await Promise.all([
983
1003
  writeFile2(path3.join(caseDirectory, "judge-trace.jsonl"), capture.stdout),
984
1004
  writeFile2(path3.join(caseDirectory, "judge-stderr.log"), capture.stderr)
@@ -990,7 +1010,7 @@ async function runLlmJudge(options, testCase, markdown, caseDirectory) {
990
1010
  usage: extractTokenUsage(capture.stdout)
991
1011
  };
992
1012
  }
993
- function buildCodexGenerationArgs(options, testCase, caseDirectory, outputSchemaPath, finalPath) {
1013
+ function buildCodexGenerationArgs(options, testCase, caseDirectory, agentCwd, outputSchemaPath, finalPath) {
994
1014
  const mcpArgs = [
995
1015
  options.cliEntry,
996
1016
  "mcp",
@@ -1013,7 +1033,7 @@ function buildCodexGenerationArgs(options, testCase, caseDirectory, outputSchema
1013
1033
  "--color",
1014
1034
  "never",
1015
1035
  "--cd",
1016
- caseDirectory,
1036
+ agentCwd,
1017
1037
  "-c",
1018
1038
  `mcp_servers.docblocks.command=${tomlString(process.execPath)}`,
1019
1039
  "-c",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/docblocks-cli",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "Build, preview, convert, render, inspect, and automate documents",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -39,24 +39,25 @@
39
39
  "node": ">=22.14.0"
40
40
  },
41
41
  "files": [
42
- "dist"
42
+ "dist",
43
+ "THIRD_PARTY_NOTICES.txt"
43
44
  ],
44
45
  "scripts": {
45
46
  "build": "tsup",
46
47
  "typecheck": "tsc --noEmit"
47
48
  },
48
49
  "dependencies": {
49
- "@bendyline/docblocks": "2.2.0",
50
- "@bendyline/squisq": "2.3.2",
51
- "@bendyline/squisq-cli": "2.3.2",
52
- "@bendyline/squisq-formats": "2.3.2",
53
- "@bendyline/squisq-react": "2.3.2",
54
- "@bendyline/squisq-video": "2.2.2",
50
+ "@bendyline/docblocks": "2.2.2",
51
+ "@bendyline/squisq": "2.4.1",
52
+ "@bendyline/squisq-cli": "2.4.1",
53
+ "@bendyline/squisq-formats": "2.3.5",
54
+ "@bendyline/squisq-react": "2.4.1",
55
+ "@bendyline/squisq-video": "2.2.5",
55
56
  "@modelcontextprotocol/sdk": "1.29.0",
56
57
  "commander": "13.1.0",
57
58
  "jszip": "3.10.1",
58
- "playwright-core": "1.58.2",
59
59
  "pdf-lib": "1.17.1",
60
+ "playwright-core": "1.61.1",
60
61
  "zod": "3.25.76"
61
62
  }
62
63
  }