dotmd-cli 0.27.1 → 0.28.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotmd-cli",
3
- "version": "0.27.1",
3
+ "version": "0.28.0",
4
4
  "description": "CLI for managing markdown documents with YAML frontmatter — index, query, validate, graph, export, Notion sync, AI summaries.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,7 +29,8 @@ export function replaceFrontmatter(raw, newFrontmatter) {
29
29
  //
30
30
  // Supports:
31
31
  // inline scalars `key: value`
32
- // arrays `key:\n - item\n - item`
32
+ // inline flow arrays `key: []` / `key: [a, b, "c, d"]`
33
+ // block arrays `key:\n - item\n - item`
33
34
  // folded block scalar `key: >\n one line\n continues` → "one line continues"
34
35
  // literal block scalar `key: |\n one\n two` → "one\ntwo"
35
36
  // chomping indicators `>-`, `|-` (strip), `>+`, `|+` (keep), default (clip to one trailing \n)
@@ -73,10 +74,18 @@ export function parseSimpleFrontmatter(text, warnings) {
73
74
  if (!trimmedValue) {
74
75
  data[key] = [];
75
76
  currentArrayKey = key;
76
- } else {
77
- data[key] = parseScalar(trimmedValue);
77
+ continue;
78
+ }
79
+
80
+ const flowArray = parseFlowArray(trimmedValue);
81
+ if (flowArray !== null) {
82
+ data[key] = flowArray;
78
83
  currentArrayKey = null;
84
+ continue;
79
85
  }
86
+
87
+ data[key] = parseScalar(trimmedValue);
88
+ currentArrayKey = null;
80
89
  continue;
81
90
  }
82
91
 
@@ -169,6 +178,41 @@ function collectBlockScalar(lines, startIdx, style, chomp) {
169
178
  return { value, consumed: i - startIdx };
170
179
  }
171
180
 
181
+ // Parses a YAML flow sequence like `[]`, `[a, b]`, `[a, "b, c", 'd']`.
182
+ // Returns an array on success, or null if the value isn't a well-formed
183
+ // `[…]` flow sequence (caller falls back to scalar parsing).
184
+ function parseFlowArray(value) {
185
+ if (!value.startsWith('[') || !value.endsWith(']')) return null;
186
+ const inner = value.slice(1, -1);
187
+ if (!inner.trim()) return [];
188
+
189
+ const items = [];
190
+ let current = '';
191
+ let quote = null;
192
+ for (let i = 0; i < inner.length; i++) {
193
+ const c = inner[i];
194
+ if (quote) {
195
+ current += c;
196
+ if (c === quote) quote = null;
197
+ continue;
198
+ }
199
+ if (c === "'" || c === '"') {
200
+ quote = c;
201
+ current += c;
202
+ continue;
203
+ }
204
+ if (c === ',') {
205
+ items.push(parseScalar(current.trim()));
206
+ current = '';
207
+ continue;
208
+ }
209
+ current += c;
210
+ }
211
+ if (quote !== null) return null; // unterminated quote — not a valid flow array
212
+ items.push(parseScalar(current.trim()));
213
+ return items;
214
+ }
215
+
172
216
  function parseScalar(value) {
173
217
  let unquoted = value;
174
218
  if (value.length > 1 &&
package/src/new.mjs CHANGED
@@ -17,12 +17,12 @@ const BUILTIN_TEMPLATES = {
17
17
  `status: ${s}`,
18
18
  `created: ${d}`,
19
19
  `updated: ${d}`,
20
- 'modules: []',
21
- 'surfaces: []',
20
+ 'modules:',
21
+ 'surfaces:',
22
22
  'domain:',
23
23
  'audience: internal',
24
- 'related_plans: []',
25
- 'related_docs: []',
24
+ 'related_plans:',
25
+ 'related_docs:',
26
26
  ].join('\n'),
27
27
  body: (t, ctx) => `
28
28
  # ${t}
@@ -50,13 +50,13 @@ const BUILTIN_TEMPLATES = {
50
50
  `status: ${s}`,
51
51
  `created: ${d}`,
52
52
  `updated: ${d}`,
53
- 'surfaces: []',
54
- 'modules: []',
53
+ 'surfaces:',
54
+ 'modules:',
55
55
  'domain:',
56
56
  'audience: internal',
57
57
  'parent_plan:',
58
- 'related_plans: []',
59
- 'related_docs: []',
58
+ 'related_plans:',
59
+ 'related_docs:',
60
60
  'current_state:',
61
61
  'next_step:',
62
62
  ].join('\n'),
@@ -132,7 +132,7 @@ Status markers (put in heading text):
132
132
  `created: ${d}`,
133
133
  `dotmd_version: ${pkg.version}`,
134
134
  `context: ${ctx?.title ? `"${ctx.title.replace(/"/g, '\\"')}"` : ''}`,
135
- 'related_plans: []',
135
+ 'related_plans:',
136
136
  ].join('\n'),
137
137
  body: (t, ctx) => `\n${ctx?.bodyInput ?? '<!-- prompt body -->'}\n`,
138
138
  },
package/src/validate.mjs CHANGED
@@ -29,7 +29,7 @@ export function validateDoc(doc, frontmatter, headingTitle, config) {
29
29
  const rootSet = config.rootValidStatuses?.get(doc.root);
30
30
  const combined = new Set([...(typeSet ?? []), ...(rootSet ?? config.validStatuses)]);
31
31
  const hint = `valid: ${[...combined].join(', ')}`;
32
- doc.warnings.push({ path: doc.path, level: 'warning', message: `Unknown status \`${doc.status}\`; ${hint}.` });
32
+ doc.errors.push({ path: doc.path, level: 'error', message: `Unknown status \`${doc.status}\`; ${hint}.` });
33
33
  }
34
34
 
35
35
  const knownStatus = isValidStatus(doc.status, doc.root, config, doc.type);