summaryrefslogtreecommitdiff
path: root/subagents/frontmatter.lua
diff options
context:
space:
mode:
Diffstat (limited to 'subagents/frontmatter.lua')
-rw-r--r--subagents/frontmatter.lua44
1 files changed, 39 insertions, 5 deletions
diff --git a/subagents/frontmatter.lua b/subagents/frontmatter.lua
index 94fe2ac..8740870 100644
--- a/subagents/frontmatter.lua
+++ b/subagents/frontmatter.lua
@@ -13,8 +13,9 @@
-- (a lone `---` at the top of a prose file is a horizontal rule, not a
-- broken header, so this case is deliberately silent)
-- * empty fenced block -> empty mapping, no warning
--- * lyaml missing or erroring -> body after the fence, warning returned
+-- * parser missing or erroring-> body after the fence, warning returned
-- * YAML document not a map -> body after the fence, warning returned
+-- * unresolved anchor/alias -> that key dropped, warning returned
--
-- In the warning cases the fenced block is dropped rather than folded back
-- into the body: an unparseable header is noise the child agent should not be
@@ -27,6 +28,34 @@ local function trim(s)
return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end
+-- tinyyaml parses a subset of YAML: it does not resolve anchors (`&a`) or
+-- aliases (`*a`). Rather than failing on them it hands back the raw token as
+-- a plain string, so `name: *base` arrives here as the literal "*base" and
+-- would sail through any `type(v) == "string"` check to become a profile's
+-- actual name. Detect that shape and drop those keys so the caller falls back
+-- to its defaults instead of adopting a bogus value.
+--
+-- The match is deliberately narrow -- a whole value that is exactly `*word`,
+-- or one opening with `&word ` -- so ordinary prose containing `*` or `&`
+-- (`'fetch & parse'`, `'a *b* c'`) is left alone.
+local function strip_unresolved_aliases(data)
+ local hits = {}
+ for k, v in pairs(data) do
+ if type(v) == "string"
+ and (v:match("^%*[%w_%-]+$") or v:match("^&[%w_%-]+%s")) then
+ hits[#hits + 1] = tostring(k)
+ end
+ end
+ if #hits == 0 then
+ return nil
+ end
+ table.sort(hits)
+ for _, k in ipairs(hits) do
+ data[k] = nil
+ end
+ return table.concat(hits, ", ")
+end
+
-- Iterate lines, yielding the line plus its start offset and the offset just
-- past its newline, so the caller can slice the original text exactly.
local function lines(text)
@@ -79,17 +108,22 @@ function M.parse(text)
return {}, body, nil
end
- local ok_lyaml, lyaml = pcall(require, "lyaml")
- if not ok_lyaml then
- return nil, body, "lyaml is not installed; ignoring the YAML frontmatter"
+ local ok_yaml, yaml = pcall(require, "tinyyaml")
+ if not ok_yaml then
+ return nil, body, "tinyyaml is not installed; ignoring the YAML frontmatter"
end
- local ok, data = pcall(lyaml.load, block)
+ local ok, data = pcall(yaml.parse, block)
if not ok then
return nil, body, "YAML frontmatter did not parse: " .. tostring(data)
end
if type(data) ~= "table" then
return nil, body, "YAML frontmatter is not a mapping; ignoring it"
end
+ local aliased = strip_unresolved_aliases(data)
+ if aliased then
+ return data, body,
+ "YAML anchors/aliases are not supported; ignoring: " .. aliased
+ end
return data, body, nil
end