drafter-mcp 0.25.0 → 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 +44 -7
  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.25.0";
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));
@@ -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.25.0",
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",