@bendyline/docblocks-cli 2.6.0 → 2.6.1

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.
@@ -15,11 +15,11 @@ This notice is included in the published npm tarball. Transitive packages instal
15
15
  | Package | Version | License | Source |
16
16
  | --- | --- | --- | --- |
17
17
  | @antfu/install-pkg | 1.1.0 | MIT | https://github.com/antfu/install-pkg |
18
- | @bendyline/squisq | 2.11.1 | MIT | https://github.com/bendyline/squisq |
19
- | @bendyline/squisq-cli | 2.8.1 | MIT | https://github.com/bendyline/squisq |
20
- | @bendyline/squisq-formats | 2.6.1 | MIT | https://github.com/bendyline/squisq |
21
- | @bendyline/squisq-react | 2.11.1 | MIT | https://github.com/bendyline/squisq |
22
- | @bendyline/squisq-video | 2.3.4 | MIT | https://github.com/bendyline/squisq |
18
+ | @bendyline/squisq | 2.11.3 | MIT | https://github.com/bendyline/squisq |
19
+ | @bendyline/squisq-cli | 2.8.3 | MIT | https://github.com/bendyline/squisq |
20
+ | @bendyline/squisq-formats | 2.6.3 | MIT | https://github.com/bendyline/squisq |
21
+ | @bendyline/squisq-react | 2.11.3 | MIT | https://github.com/bendyline/squisq |
22
+ | @bendyline/squisq-video | 2.3.6 | MIT | https://github.com/bendyline/squisq |
23
23
  | @braintree/sanitize-url | 7.1.2 | MIT | https://github.com/braintree/sanitize-url |
24
24
  | @chevrotain/types | 11.1.2 | Apache-2.0 | https://github.com/Chevrotain/chevrotain |
25
25
  | @ffmpeg/ffmpeg | 0.12.15 | MIT | https://github.com/ffmpegwasm/ffmpeg.wasm |
@@ -403,7 +403,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
403
403
  SOFTWARE.
404
404
 
405
405
  ==============================================================================
406
- Components: @bendyline/squisq-cli@2.8.1, @bendyline/squisq-formats@2.6.1, @bendyline/squisq-react@2.11.1, @bendyline/squisq-video@2.3.4, @bendyline/squisq@2.11.1
406
+ Components: @bendyline/squisq-cli@2.8.3, @bendyline/squisq-formats@2.6.3, @bendyline/squisq-react@2.11.3, @bendyline/squisq-video@2.3.6, @bendyline/squisq@2.11.3
407
407
  Source files: node_modules/@bendyline/squisq-cli/LICENSE, node_modules/@bendyline/squisq-formats/LICENSE, node_modules/@bendyline/squisq-react/LICENSE, node_modules/@bendyline/squisq-video/LICENSE, node_modules/@bendyline/squisq/LICENSE
408
408
  ==============================================================================
409
409
  MIT License
@@ -673,7 +673,7 @@ This software contains code derived from the Puppeteer project (https://github.c
673
673
  available under the Apache 2.0 license (https://github.com/puppeteer/puppeteer/blob/master/LICENSE).
674
674
 
675
675
  ==============================================================================
676
- Components: @bendyline/squisq-cli@2.8.1
676
+ Components: @bendyline/squisq-cli@2.8.3
677
677
  Source files: node_modules/@bendyline/squisq-cli/NOTICE.md
678
678
  ==============================================================================
679
679
  # Third-Party Notices for @bendyline/squisq-cli
@@ -693,7 +693,7 @@ Copyright and complete license texts for these dependencies are included in
693
693
  their respective npm distributions and source repositories.
694
694
 
695
695
  ==============================================================================
696
- Components: @bendyline/squisq-cli@2.8.1
696
+ Components: @bendyline/squisq-cli@2.8.3
697
697
  Source files: node_modules/@bendyline/squisq-cli/THIRD_PARTY_LICENSES.txt
698
698
  ==============================================================================
699
699
  THIRD-PARTY LICENSES FOR @bendyline/squisq-cli
@@ -5181,7 +5181,7 @@ The above copyright notice and this permission notice shall be included in all c
5181
5181
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5182
5182
 
5183
5183
  ==============================================================================
5184
- Components: @bendyline/squisq-formats@2.6.1
5184
+ Components: @bendyline/squisq-formats@2.6.3
5185
5185
  Source files: node_modules/@bendyline/squisq-formats/NOTICE.md
5186
5186
  ==============================================================================
5187
5187
  # Third-Party Notices for @bendyline/squisq-formats
@@ -5207,7 +5207,7 @@ texts for these dependencies are included in their respective npm
5207
5207
  distributions and source repositories.
5208
5208
 
5209
5209
  ==============================================================================
5210
- Components: @bendyline/squisq-formats@2.6.1
5210
+ Components: @bendyline/squisq-formats@2.6.3
5211
5211
  Source files: node_modules/@bendyline/squisq-formats/THIRD_PARTY_LICENSES.txt
5212
5212
  ==============================================================================
5213
5213
  THIRD-PARTY LICENSES FOR @bendyline/squisq-formats
@@ -5389,7 +5389,7 @@ Awesome, nor vice versa. **Please do not use brand logos for any purpose except
5389
5389
  to represent the company, product, or service to which they refer.**
5390
5390
 
5391
5391
  ==============================================================================
5392
- Components: @bendyline/squisq-react@2.11.1
5392
+ Components: @bendyline/squisq-react@2.11.3
5393
5393
  Source files: node_modules/@bendyline/squisq-react/NOTICE.md
5394
5394
  ==============================================================================
5395
5395
  # Third-Party Notices for @bendyline/squisq-react
@@ -5414,7 +5414,7 @@ third-party license texts for the complete standalone bundle graph are shipped
5414
5414
  in THIRD_PARTY_LICENSES.txt.
5415
5415
 
5416
5416
  ==============================================================================
5417
- Components: @bendyline/squisq-react@2.11.1
5417
+ Components: @bendyline/squisq-react@2.11.3
5418
5418
  Source files: node_modules/@bendyline/squisq-react/THIRD_PARTY_LICENSES.txt
5419
5419
  ==============================================================================
5420
5420
  THIRD-PARTY LICENSES FOR @bendyline/squisq-react
@@ -9951,7 +9951,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
9951
9951
  SOFTWARE.
9952
9952
 
9953
9953
  ==============================================================================
9954
- Components: @bendyline/squisq-video@2.3.4
9954
+ Components: @bendyline/squisq-video@2.3.6
9955
9955
  Source files: node_modules/@bendyline/squisq-video/NOTICE.md
9956
9956
  ==============================================================================
9957
9957
  # Third-Party Notices for @bendyline/squisq-video
@@ -9976,7 +9976,7 @@ Copyright and complete license texts for the listed dependencies are included
9976
9976
  in their respective npm distributions and source repositories.
9977
9977
 
9978
9978
  ==============================================================================
9979
- Components: @bendyline/squisq-video@2.3.4
9979
+ Components: @bendyline/squisq-video@2.3.6
9980
9980
  Source files: node_modules/@bendyline/squisq-video/THIRD_PARTY_LICENSES.txt
9981
9981
  ==============================================================================
9982
9982
  THIRD-PARTY LICENSES FOR @bendyline/squisq-video
@@ -9988,7 +9988,7 @@ repository license, the pinned upstream copy is vendored and identified below.
9988
9988
  COMPONENTS
9989
9989
 
9990
9990
  ==============================================================================
9991
- Components: @bendyline/squisq@2.11.1
9991
+ Components: @bendyline/squisq@2.11.3
9992
9992
  Source files: node_modules/@bendyline/squisq/NOTICE.md
9993
9993
  ==============================================================================
9994
9994
  # Third-Party Notices for @bendyline/squisq
@@ -10019,7 +10019,7 @@ third-party license texts for bundled code and data are shipped in
10019
10019
  THIRD_PARTY_LICENSES.txt.
10020
10020
 
10021
10021
  ==============================================================================
10022
- Components: @bendyline/squisq@2.11.1
10022
+ Components: @bendyline/squisq@2.11.3
10023
10023
  Source files: node_modules/@bendyline/squisq/THIRD_PARTY_LICENSES.txt
10024
10024
  ==============================================================================
10025
10025
  THIRD-PARTY LICENSES FOR @bendyline/squisq
package/dist/bin.js CHANGED
@@ -169,6 +169,13 @@ import {
169
169
  MCP_WIRE_LIMITS,
170
170
  parseConversionResult
171
171
  } from "@bendyline/docblocks/mcp";
172
+ function artifactReferenceError(message) {
173
+ return Object.assign(new Error(message), {
174
+ code: "invalid-artifact-reference",
175
+ hint: "Use the exact artifact.uri returned by a successful convert_document, create_document_bundle, or preview_document call in this MCP session. Do not invent a URI or use a content hash as an id. For an earlier saved file, call list_roots and use a file source with rootId and path; if it was not saved, convert the source again.",
176
+ retryable: false
177
+ });
178
+ }
172
179
  function artifactId(uriOrId) {
173
180
  const artifactIdPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
174
181
  if (artifactIdPattern.test(uriOrId)) {
@@ -178,11 +185,11 @@ function artifactId(uriOrId) {
178
185
  try {
179
186
  parsed = new URL(uriOrId);
180
187
  } catch {
181
- throw new Error("Invalid MCP artifact URI");
188
+ throw artifactReferenceError("Invalid MCP artifact URI");
182
189
  }
183
190
  const id = parsed.pathname.slice(1);
184
191
  if (parsed.protocol !== "docblocks:" || parsed.hostname !== "artifacts" || parsed.username !== "" || parsed.password !== "" || parsed.port !== "" || parsed.search !== "" || parsed.hash !== "" || parsed.pathname !== `/${id}` || !artifactIdPattern.test(id) || uriOrId !== `docblocks://artifacts/${id}`) {
185
- throw new Error("Invalid MCP artifact URI");
192
+ throw artifactReferenceError("Invalid MCP artifact URI");
186
193
  }
187
194
  return id;
188
195
  }
@@ -535,7 +542,7 @@ var init_artifact_store = __esm({
535
542
  findRecordLocked(uriOrId) {
536
543
  const id = artifactId(uriOrId);
537
544
  const stored = this.records.get(id);
538
- if (!stored) throw new Error("Unknown or expired MCP artifact");
545
+ if (!stored) throw artifactReferenceError("Unknown or expired MCP artifact");
539
546
  return stored;
540
547
  }
541
548
  takeExpiredLocked() {
@@ -1567,9 +1574,9 @@ var init_document_service = __esm({
1567
1574
  markdown = importedMarkdown;
1568
1575
  }
1569
1576
  const { parseMarkdown: parseMarkdown2 } = await import("@bendyline/squisq/markdown");
1570
- const { markdownToDoc: markdownToDoc2 } = await import("@bendyline/squisq/doc");
1577
+ const { markdownToDoc: markdownToDoc3 } = await import("@bendyline/squisq/doc");
1571
1578
  const markdownDoc = parseMarkdown2(markdown);
1572
- const doc = markdownToDoc2(markdownDoc, {
1579
+ const doc = markdownToDoc3(markdownDoc, {
1573
1580
  defaultTemplate: "content",
1574
1581
  autoTemplates: false
1575
1582
  });
@@ -1983,7 +1990,7 @@ async function authoringDiagnostics(prepared, stage, format, signal) {
1983
1990
  totalBlocks: analyzedBlocks.length
1984
1991
  });
1985
1992
  const renderedText = materialized.layers.filter((layer) => layer.type === "text").map((layer) => layer.content.text).join("\n");
1986
- if (!normalizedText(renderedText).includes(normalizedText(body))) {
1993
+ if (!renderedBodyIncludes(renderedText, body)) {
1987
1994
  diagnostics.push({
1988
1995
  code: "rendered-content-omitted",
1989
1996
  severity: "error",
@@ -2016,6 +2023,10 @@ async function authoringDiagnostics(prepared, stage, format, signal) {
2016
2023
  }
2017
2024
  return diagnostics;
2018
2025
  }
2026
+ function renderedBodyIncludes(renderedText, body) {
2027
+ const undecorated = renderedText.replace(/(^|\n)[\t ]*(?:[•◦▪]|\d+[.)])[\t ]+/gu, "$1");
2028
+ return normalizedText(undecorated).includes(normalizedText(body));
2029
+ }
2019
2030
  function normalizedText(value) {
2020
2031
  return value.normalize("NFKC").replace(/\s+/gu, " ").trim().toLocaleLowerCase("en-US");
2021
2032
  }
@@ -3463,6 +3474,30 @@ var init_rendered_conversion = __esm({
3463
3474
  }
3464
3475
  });
3465
3476
 
3477
+ // src/mcp/pptx-source.ts
3478
+ import { markdownToDoc as markdownToDoc2 } from "@bendyline/squisq/doc";
3479
+ function preparePptxSource(markdown, slideBreak, autoTemplates) {
3480
+ const maxDepth = slideBreak === "h1" ? 1 : slideBreak === "h2" ? 2 : 6;
3481
+ const grouped = {
3482
+ ...markdown,
3483
+ children: markdown.children.map(
3484
+ (node) => node.type === "heading" && node.depth > maxDepth ? {
3485
+ type: "paragraph",
3486
+ children: [{ type: "strong", children: node.children }]
3487
+ } : node
3488
+ )
3489
+ };
3490
+ return {
3491
+ markdownDoc: grouped,
3492
+ doc: markdownToDoc2(grouped, { generateCoverBlock: false, autoTemplates })
3493
+ };
3494
+ }
3495
+ var init_pptx_source = __esm({
3496
+ "src/mcp/pptx-source.ts"() {
3497
+ "use strict";
3498
+ }
3499
+ });
3500
+
3466
3501
  // src/mcp/conversion-service.ts
3467
3502
  import { createHash as createHash6 } from "crypto";
3468
3503
  import { DOCBLOCKS_MCP_WIRE_VERSION as DOCBLOCKS_MCP_WIRE_VERSION3 } from "@bendyline/docblocks/mcp";
@@ -3507,6 +3542,9 @@ async function convertPreparedDocument(artifacts, prepared, request, signal, pro
3507
3542
  for (let index = 0; index < request.targets.length; index += 1) {
3508
3543
  throwIfAborted5(signal);
3509
3544
  const target = request.targets[index];
3545
+ const slideBreak = target.options?.slideBreak ?? "h1";
3546
+ const pptxSource = target.format === "pptx" && (slideBreak === "h1" || slideBreak === "h2" || slideBreak === "heading") ? preparePptxSource(prepared.markdownDoc, slideBreak, request.autoTemplates) : void 0;
3547
+ const targetDocument = pptxSource ? { ...prepared, ...pptxSource } : prepared;
3510
3548
  const definition = linkedRegistry.get(target.format);
3511
3549
  if (!definition) throw new Error(`Unknown conversion target "${target.format}"`);
3512
3550
  if (!definition.exportDoc) throw new Error(`Format "${target.format}" is not export-capable`);
@@ -3545,7 +3583,7 @@ async function convertPreparedDocument(artifacts, prepared, request, signal, pro
3545
3583
  }
3546
3584
  };
3547
3585
  const converted = usesDocumentRasterizer(target.format, fidelity) ? await dependencies.convertRenderedDocument(
3548
- prepared,
3586
+ targetDocument,
3549
3587
  target.format,
3550
3588
  fidelity,
3551
3589
  target.options ?? {},
@@ -3561,7 +3599,15 @@ async function convertPreparedDocument(artifacts, prepared, request, signal, pro
3561
3599
  `${target.format}: ${message}`
3562
3600
  )
3563
3601
  ) : await (async () => {
3564
- nativePrepared ?? (nativePrepared = await dependencies.prepareNativeConversion(
3602
+ const targetPrepared = pptxSource ? await dependencies.prepareNativeConversion(
3603
+ {
3604
+ kind: "doc",
3605
+ doc: pptxSource.doc,
3606
+ container: prepared.container,
3607
+ baseName: prepared.baseName
3608
+ },
3609
+ nativePrepareOptions
3610
+ ) : nativePrepared ?? (nativePrepared = await dependencies.prepareNativeConversion(
3565
3611
  {
3566
3612
  kind: "markdown",
3567
3613
  markdown: prepared.markdownDoc,
@@ -3571,7 +3617,7 @@ async function convertPreparedDocument(artifacts, prepared, request, signal, pro
3571
3617
  nativePrepareOptions
3572
3618
  ));
3573
3619
  try {
3574
- return await nativePrepared.convert(target.format, {
3620
+ return await targetPrepared.convert(target.format, {
3575
3621
  signal,
3576
3622
  title: request.title,
3577
3623
  formatOptions: { [target.format]: formatOptions }
@@ -3883,6 +3929,7 @@ var init_conversion_service = __esm({
3883
3929
  init_document_service();
3884
3930
  init_intelligence();
3885
3931
  init_rendered_conversion();
3932
+ init_pptx_source();
3886
3933
  MCP_FORMAT_FIDELITIES = {
3887
3934
  md: ["semantic"],
3888
3935
  docx: ["semantic", "editable-native"],
@@ -4126,6 +4173,39 @@ var init_progress = __esm({
4126
4173
  }
4127
4174
  });
4128
4175
 
4176
+ // src/mcp/preview-content.ts
4177
+ async function inlinePreviewContent(result, artifacts, signal) {
4178
+ const content = [];
4179
+ let remaining = MAX_INLINE_PREVIEW_BYTES;
4180
+ for (const item of result.items) {
4181
+ signal?.throwIfAborted();
4182
+ const encodedSize = 4 * Math.ceil(item.artifact.size / 3);
4183
+ if (encodedSize > remaining) {
4184
+ content.push({
4185
+ type: "text",
4186
+ text: `Preview item ${item.index} is available by resource link but was not inlined because of the response-size budget. Request startIndex: ${item.index}, maxItems: 1 and smaller width/height to inspect its pixels.`
4187
+ });
4188
+ continue;
4189
+ }
4190
+ const bytes = await artifacts.read(item.artifact.uri, signal);
4191
+ const data = bytes.toString("base64");
4192
+ remaining -= data.length;
4193
+ content.push({
4194
+ type: "text",
4195
+ text: `Preview item ${item.index}${item.label ? `: ${item.label}` : ""} (${result.previewBasis})`
4196
+ });
4197
+ content.push({ type: "image", mimeType: item.artifact.mimeType, data });
4198
+ }
4199
+ return content;
4200
+ }
4201
+ var MAX_INLINE_PREVIEW_BYTES;
4202
+ var init_preview_content = __esm({
4203
+ "src/mcp/preview-content.ts"() {
4204
+ "use strict";
4205
+ MAX_INLINE_PREVIEW_BYTES = 4 * 1024 * 1024;
4206
+ }
4207
+ });
4208
+
4129
4209
  // src/mcp/style-guidance.ts
4130
4210
  var STYLE_SELECTION_GUIDANCE, TRANSFORM_SELECTION_GUIDANCE, MOTION_SELECTION_GUIDANCE;
4131
4211
  var init_style_guidance = __esm({
@@ -4430,7 +4510,8 @@ function registerAgenticTools(server, context) {
4430
4510
  return {
4431
4511
  content: [
4432
4512
  { type: "text", text: JSON.stringify(result) },
4433
- ...result.items.map((item) => artifactLink(item.artifact))
4513
+ ...result.items.map((item) => artifactLink(item.artifact)),
4514
+ ...await inlinePreviewContent(result, context.artifacts, operationSignal)
4434
4515
  ],
4435
4516
  structuredContent: asStructuredContent(successResult(result))
4436
4517
  };
@@ -5294,6 +5375,7 @@ var init_agentic_tools = __esm({
5294
5375
  init_preview_service();
5295
5376
  init_error_result();
5296
5377
  init_progress();
5378
+ init_preview_content();
5297
5379
  init_output_bounds();
5298
5380
  init_style_guidance();
5299
5381
  READ_ONLY = {
@@ -5351,8 +5433,8 @@ var init_agentic_tools = __esm({
5351
5433
  format: z.literal("pptx"),
5352
5434
  fidelity: fidelitySchemas.pptx.optional(),
5353
5435
  ...metadataFields,
5354
- slideBreak: z.enum(["h1", "h2", "heading"]).optional().describe(
5355
- "Heading depths that start slides. Headings alone create slide boundaries; do not add --- between them unless a visible horizontal rule is intended."
5436
+ slideBreak: z.enum(["h1", "h2", "heading"]).default("h1").describe(
5437
+ "Defaults to h1: author one H1 per slide; deeper headings remain body text and no extra cover is inserted. h2 breaks at H1/H2; heading breaks at any depth. Include a title slide as an authored heading; do not add --- between heading-based slides."
5356
5438
  ),
5357
5439
  defaultFont: z.string().max(256).optional(),
5358
5440
  defaultFontSize: z.number().min(6).max(96).optional(),
@@ -7366,10 +7448,10 @@ function throwIfAborted2(signal) {
7366
7448
  throwIfAborted(signal, "Document conversion was cancelled");
7367
7449
  }
7368
7450
  async function applyTransformToMarkdown(markdownDoc, container, transformStyle, themeId) {
7369
- const { markdownToDoc: markdownToDoc2, docToMarkdown } = await import("@bendyline/squisq/doc");
7451
+ const { markdownToDoc: markdownToDoc3, docToMarkdown } = await import("@bendyline/squisq/doc");
7370
7452
  const { readFrontmatterThemeId } = await import("@bendyline/squisq/markdown");
7371
7453
  const { applyTransform, extractDocImages } = await import("@bendyline/squisq/transform");
7372
- const doc = markdownToDoc2(markdownDoc);
7454
+ const doc = markdownToDoc3(markdownDoc);
7373
7455
  const images = extractDocImages(doc.blocks);
7374
7456
  const effectiveTheme = themeId ?? readFrontmatterThemeId(markdownDoc.frontmatter);
7375
7457
  const result = applyTransform(doc, transformStyle, { themeId: effectiveTheme, images });
package/dist/eval/cli.js CHANGED
@@ -38,7 +38,8 @@ Include a clear opening thesis, a compact scorecard, insights rather than repeat
38
38
  minWords: 220,
39
39
  maxWords: 650,
40
40
  maxWordsPerSection: 95,
41
- minVisualTemplates: 2,
41
+ // Layouts may be chosen by autoTemplates; annotation count is not visual quality.
42
+ minVisualTemplates: 0,
42
43
  requiredPhrases: ["18,420", "71%", "$3.8M", "49%", "23%", "31%", "permissions"]
43
44
  }
44
45
  },
@@ -63,7 +64,8 @@ Cover: a plain-language definition, an opening scenario, a four-question risk sc
63
64
  minWords: 240,
64
65
  maxWords: 700,
65
66
  maxWordsPerSection: 90,
66
- minVisualTemplates: 2,
67
+ // Layouts may be chosen by autoTemplates; annotation count is not visual quality.
68
+ minVisualTemplates: 0,
67
69
  requiredPhrases: ["accountable", "confidential", "escalat", "four", "one-week"]
68
70
  }
69
71
  },
@@ -422,7 +424,7 @@ var HEADING_PATTERN = /^(#{1,6})\s+(.+)$/gm;
422
424
  var TEMPLATE_PATTERN = /\{\[([A-Za-z0-9_-]+)/g;
423
425
  function judgeMarkdown(markdown, testCase) {
424
426
  const words = countWords(markdown);
425
- const sections = markdownSections(markdown);
427
+ const sections = markdownSections(markdown, testCase.targetFormat === "pptx" ? 1 : 6);
426
428
  const headings = [...markdown.matchAll(HEADING_PATTERN)];
427
429
  const templates = [...markdown.matchAll(TEMPLATE_PATTERN)].map((match) => match[1]);
428
430
  const visualTemplates = templates.filter((template) => template !== "content");
@@ -440,7 +442,7 @@ function judgeMarkdown(markdown, testCase) {
440
442
  ),
441
443
  rangeCheck(
442
444
  "section-count",
443
- headings.length,
445
+ sections.length,
444
446
  testCase.expectation.minItems,
445
447
  testCase.expectation.maxItems,
446
448
  true,
@@ -482,6 +484,7 @@ function judgeMarkdown(markdown, testCase) {
482
484
  return summarizeChecks(checks, {
483
485
  wordCount: words,
484
486
  headingCount: headings.length,
487
+ sectionCount: sections.length,
485
488
  templateAnnotationCount: templates.length,
486
489
  visualTemplateCount: visualTemplates.length,
487
490
  denseSectionCount: denseSections.length
@@ -490,8 +493,10 @@ function judgeMarkdown(markdown, testCase) {
490
493
  function countWords(value) {
491
494
  return value.trim().match(/[\p{L}\p{N}][\p{L}\p{N}'’.-]*/gu)?.length ?? 0;
492
495
  }
493
- function markdownSections(markdown) {
494
- const matches = [...markdown.matchAll(HEADING_PATTERN)];
496
+ function markdownSections(markdown, maxDepth = 6) {
497
+ const matches = [...markdown.matchAll(HEADING_PATTERN)].filter(
498
+ (match) => match[1].length <= maxDepth
499
+ );
495
500
  return matches.map((match, index) => ({
496
501
  heading: match[2],
497
502
  body: markdown.slice((match.index ?? 0) + match[0].length, matches[index + 1]?.index)
@@ -1083,7 +1088,8 @@ The deterministic observations below are authoritative. Do not recount them or c
1083
1088
 
1084
1089
  Deterministic observations:
1085
1090
  - Word count: ${String(deterministic.metrics.wordCount)} (acceptance envelope ${testCase.expectation.minWords}-${testCase.expectation.maxWords})
1086
- - Heading/section count: ${String(deterministic.metrics.headingCount)} (acceptance envelope ${testCase.expectation.minItems}-${testCase.expectation.maxItems})
1091
+ - Section count${testCase.targetFormat === "pptx" ? " (H1 slide boundaries)" : ""}: ${String(deterministic.metrics.sectionCount)} (acceptance envelope ${testCase.expectation.minItems}-${testCase.expectation.maxItems})
1092
+ - All headings, including subordinate headings within a slide: ${String(deterministic.metrics.headingCount)} (diagnostic only; do not compare this count with the slide target)
1087
1093
  - Sections over ${testCase.expectation.maxWordsPerSection} words: ${String(deterministic.metrics.denseSectionCount)}
1088
1094
  - Non-content Squisq template annotations: ${String(deterministic.metrics.visualTemplateCount)} (minimum ${testCase.expectation.minVisualTemplates})
1089
1095
  - Deterministic acceptance: ${deterministic.passed ? "pass" : "fail"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/docblocks-cli",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Build, preview, convert, render, inspect, and automate documents",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -47,12 +47,12 @@
47
47
  "typecheck": "tsc --noEmit"
48
48
  },
49
49
  "dependencies": {
50
- "@bendyline/docblocks": "2.6.0",
51
- "@bendyline/squisq": "2.11.1",
52
- "@bendyline/squisq-cli": "2.8.1",
53
- "@bendyline/squisq-formats": "2.6.1",
54
- "@bendyline/squisq-react": "2.11.1",
55
- "@bendyline/squisq-video": "2.3.4",
50
+ "@bendyline/docblocks": "2.6.1",
51
+ "@bendyline/squisq": "2.11.3",
52
+ "@bendyline/squisq-cli": "2.8.3",
53
+ "@bendyline/squisq-formats": "2.6.3",
54
+ "@bendyline/squisq-react": "2.11.3",
55
+ "@bendyline/squisq-video": "2.3.6",
56
56
  "@modelcontextprotocol/sdk": "1.29.0",
57
57
  "commander": "13.1.0",
58
58
  "jszip": "3.10.1",