drafter-mcp 0.24.3 → 0.25.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.
Files changed (2) hide show
  1. package/drafter-mcp.js +49 -12
  2. package/package.json +1 -1
package/drafter-mcp.js CHANGED
@@ -23233,7 +23233,7 @@ function toError(value) {
23233
23233
  return value instanceof Error ? value : new Error(String(value));
23234
23234
  }
23235
23235
  // package.json
23236
- var version = "0.24.3";
23236
+ var version = "0.25.1";
23237
23237
  // ../fountain/src/inline.ts
23238
23238
  const MARKERS$1 = /[*_\\]/;
23239
23239
  const isSpace$10 = (code) => code === void 0 || /\s/.test(String.fromCharCode(code));
@@ -23395,11 +23395,11 @@ function jsonOf(meta) {
23395
23395
  }).replaceAll("/", "\\/");
23396
23396
  }
23397
23397
  /**
23398
- * Where the existing block is: the `/* drafter … *\/` boneyard that `parse` reads as `doc.meta`,
23399
- * the last block and alone in it. Only the boneyard itself, so the blank lines and indent around
23400
- * it stay as they were.
23398
+ * The `/* drafter … *\/` boneyard that `parse` reads as `doc.meta`, the last block and alone in it,
23399
+ * or null when there is none. Only the boneyard itself, so the blank lines and indent around it
23400
+ * stay as they were.
23401
23401
  */
23402
- function existingBlock(doc) {
23402
+ function metadataSpan(doc) {
23403
23403
  if (doc.meta === null) return null;
23404
23404
  const last = doc.blocks[doc.blocks.length - 1];
23405
23405
  if (last?.kind !== "boneyard") return null;
@@ -23428,7 +23428,7 @@ function setMeta(doc, meta) {
23428
23428
  const json = jsonOf(meta);
23429
23429
  const nl = lineBreakOf(source);
23430
23430
  const block = `${OPENER$2}${nl}${json}${nl}*/`;
23431
- const existing = existingBlock(doc);
23431
+ const existing = metadataSpan(doc);
23432
23432
  if (existing) {
23433
23433
  if (jsonOf(doc.meta) === json) return [];
23434
23434
  return [{
@@ -30174,12 +30174,44 @@ async function imported(run) {
30174
30174
  return got;
30175
30175
  }
30176
30176
  /**
30177
+ * The most paragraphs (text between blank lines) a file may have to be read: a long feature
30178
+ * script has a few thousand. Past this, a file's parse can outgrow a reader's heap
30179
+ * (READER_HEAP_MB), and in list_scripts or search_scripts the reader stopping would fail the whole
30180
+ * folder; so the file is refused alone, as too long (red/blue audit, 2026-11-03: a 3 MB file of
30181
+ * 540,000 one-line scenes and actions stopped every listing, where 360,000 still listed).
30182
+ */
30183
+ const MAX_PARAGRAPHS = 3e5;
30184
+ /** Whether `text` has more than `max` paragraphs (lines ending in LF, CR, or CRLF), in one pass. */
30185
+ function moreParagraphsThan(text, max) {
30186
+ let paragraphs = 0;
30187
+ let blank = true;
30188
+ let lineBlank = true;
30189
+ for (let i = 0; i < text.length; i++) {
30190
+ const code = text.charCodeAt(i);
30191
+ if (code === 10 || code === 13) {
30192
+ if (code === 13 && text.charCodeAt(i + 1) === 10) i++;
30193
+ blank = lineBlank;
30194
+ lineBlank = true;
30195
+ } else if (code !== 32 && code !== 9 && lineBlank) {
30196
+ lineBlank = false;
30197
+ if (blank && ++paragraphs > max) return true;
30198
+ blank = false;
30199
+ }
30200
+ }
30201
+ return false;
30202
+ }
30203
+ /**
30177
30204
  * The script inside `file`, named `name` (its shown name, which is all a refusal says), judged in
30178
30205
  * Open's order. Throws NotRead when its bytes couldn't be read, NotOpened in Open's words for a
30179
30206
  * file Open turns away, and Refused (the reader's own phrase) for text Open won't read: over 5 MB,
30180
- * not UTF-8, more than text.
30207
+ * not UTF-8, more than text, or more than MAX_PARAGRAPHS paragraphs.
30181
30208
  */
30182
30209
  async function readInside(file, name) {
30210
+ const inside = await readWhole(file, name);
30211
+ if (moreParagraphsThan(inside.text, 3e5)) throw new Refused(`it has more than ${MAX_PARAGRAPHS.toLocaleString("en-US")} paragraphs`);
30212
+ return inside;
30213
+ }
30214
+ async function readWhole(file, name) {
30183
30215
  const kind = importKindOf(name);
30184
30216
  const read = {
30185
30217
  noFollow: true,
@@ -30894,12 +30926,13 @@ function signatureLines(candidates, used = () => false) {
30894
30926
  }
30895
30927
  // ../story-map/src/mailto.ts
30896
30928
  /** What a contact may never hold: spaces, controls, and anything that ends or reshapes a URL. */
30897
- const REFUSED = /[\s?&"<>:\\/\u0000-\u001f\u007f]/;
30929
+ const REFUSED = /[\s?&"<>:\\/,;%\u0000-\u001f\u007f]/;
30898
30930
  /**
30899
30931
  * A `mailto:` link for a contact the page may link (design §10.8): one `@`, neither first nor
30900
30932
  * last; a dot in the part after it, with something on both sides of it; and no space, control
30901
- * character, `?` or `&` (which would add headers or a body to the mail), quote, angle bracket,
30902
- * colon, or slash (which could end the attribute or make it another kind of link). Else null, and
30933
+ * character, `?` or `&` (which would add headers or a body to the mail), comma, semicolon, or
30934
+ * `%` (which would add another address, plainly or encoded: red/blue audit, 2026-11-03), quote,
30935
+ * angle bracket, colon, or slash (which could end the attribute or make it another kind of link). Else null, and
30903
30936
  * the page shows the contact as text.
30904
30937
  */
30905
30938
  function mailtoOf(contact) {
@@ -34199,10 +34232,14 @@ function visibleMarkdownIn(text) {
34199
34232
  }
34200
34233
  // ../history/src/print.ts
34201
34234
  const SCREENPLAY$1 = builtins["us-screenplay"];
34202
- /** The template `doc` names in its settings, else the screenplay. */
34235
+ /**
34236
+ * The template `doc` names in its settings, else the screenplay. Only a built-in's own name: a
34237
+ * script naming `constructor` or `__proto__` got the object's prototype, and Cuts and History
34238
+ * stopped reading it (red/blue audit, 2026-11-03).
34239
+ */
34203
34240
  function templateOf(doc) {
34204
34241
  const id = doc.meta?.template;
34205
- return (typeof id === "string" ? builtins[id] : void 0) ?? SCREENPLAY$1;
34242
+ return typeof id === "string" && Object.hasOwn(builtins, id) ? builtins[id] : SCREENPLAY$1;
34206
34243
  }
34207
34244
  /**
34208
34245
  * A heading folded for matching: upper case, the locked number (`#12A#`) dropped, every dash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafter-mcp",
3
- "version": "0.24.3",
3
+ "version": "0.25.1",
4
4
  "description": "Drafter for Claude: a local, read-only MCP server that lets an AI app read the scripts in the folders the writer names.",
5
5
  "license": "MIT",
6
6
  "type": "module",