scrumrun 4.1.2 → 4.1.3

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes follow Semantic Versioning.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 4.1.3 - 2026-09-22
8
+
9
+ ### Fixed
10
+
11
+ - **`parseFrontmatter` handles multi-line arrays and YAML block lists.** The inline `allow_secrets_in: [a,\nb,\nc]` and the block form `allow_secrets_in:\n - a\n - b` used to be parsed as a single truncated string, silently disabling the whitelist. The parser now (a) keeps reading until the closing `]` for multi-line inline arrays, and (b) recognizes `- item` block lists as an array value. Existing single-line inline arrays continue to work.
12
+
7
13
  ## 4.1.2 - 2026-09-22
8
14
 
9
15
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ScrumRun gives an agent a small command surface and a precise project memory: what should be done, how each attempt happened, which decisions constrain the code, and why the architecture exists in its current form.
6
6
 
7
- **Package:** `4.1.2` · **Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
7
+ **Package:** `4.1.3` · **Method target:** `2.0.0` · **Runtime:** Node.js `>=22.13.0` · **License:** MIT
8
8
 
9
9
  **New here?** Read the [Quickstart](docs/QUICKSTART.md) — first Run in under 10 minutes, no `SPEC.md` reading required. Full docs map in [`docs/INDEX.md`](docs/INDEX.md).
10
10
 
@@ -41,12 +41,42 @@ function parseFrontmatter(text) {
41
41
  if (!match) return { explicit: {}, raw: "" };
42
42
  const body = match[1];
43
43
  const explicit = {};
44
- for (const line of body.split(/\r?\n/)) {
45
- if (!line.trim() || line.trim().startsWith("#")) continue;
44
+ const rawLines = body.split(/\r?\n/);
45
+ let index = 0;
46
+ while (index < rawLines.length) {
47
+ const line = rawLines[index];
48
+ if (!line.trim() || line.trim().startsWith("#")) { index += 1; continue; }
46
49
  const kv = line.match(/^([A-Za-z0-9_.-]+)\s*:\s*(.*)$/);
47
- if (!kv) continue;
50
+ if (!kv) { index += 1; continue; }
48
51
  const key = kv[1].trim();
49
52
  let value = kv[2].trim();
53
+
54
+ // Inline array that spans multiple lines: keep reading until we see the closing `]`.
55
+ if (value.startsWith("[") && !value.endsWith("]")) {
56
+ let acc = value;
57
+ let cursor = index + 1;
58
+ while (cursor < rawLines.length) {
59
+ acc += " " + rawLines[cursor].trim();
60
+ if (rawLines[cursor].trim().endsWith("]")) { break; }
61
+ cursor += 1;
62
+ }
63
+ value = acc;
64
+ index = cursor;
65
+ }
66
+
67
+ // YAML block list: subsequent lines start with `- item`. Consume while indented under this key.
68
+ if (value === "" && index + 1 < rawLines.length && /^\s*-\s+/.test(rawLines[index + 1])) {
69
+ const items = [];
70
+ let cursor = index + 1;
71
+ while (cursor < rawLines.length && /^\s*-\s+/.test(rawLines[cursor])) {
72
+ items.push(rawLines[cursor].replace(/^\s*-\s+/, "").trim().replace(/^['"]|['"]$/g, ""));
73
+ cursor += 1;
74
+ }
75
+ explicit[key] = items.filter(Boolean);
76
+ index = cursor;
77
+ continue;
78
+ }
79
+
50
80
  if (value.startsWith("[") && value.endsWith("]")) {
51
81
  value = value.slice(1, -1).split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter(Boolean);
52
82
  } else if (/^['"].*['"]$/.test(value)) {
@@ -55,6 +85,7 @@ function parseFrontmatter(text) {
55
85
  value = value === "true";
56
86
  }
57
87
  explicit[key] = value;
88
+ index += 1;
58
89
  }
59
90
  return { explicit, raw: body };
60
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrumrun",
3
- "version": "4.1.2",
3
+ "version": "4.1.3",
4
4
  "description": "Markdown-first Agile memory and guardrails for AI coding agents.",
5
5
  "bin": {
6
6
  "scrumrun": "bin/scrumrun.js",