parseDocsFlattenArgs supports flat JSON, the {"cmd","args"} envelope and --flag argv form.
(args []string)
| 255 | // parseDocsFlattenArgs supports flat JSON, the {"cmd","args"} envelope and |
| 256 | // --flag argv form. |
| 257 | func parseDocsFlattenArgs(args []string) (docsFlattenArgs, error) { |
| 258 | out := docsFlattenArgs{Branch: "main", Format: "text", MaxChars: 16000, StripFrontMatter: true, MaxPages: 50, MaxDepth: 2, SameHost: true, Kind: "docs"} |
| 259 | payload := strings.TrimSpace(strings.Join(args, " ")) |
| 260 | var raw map[string]json.RawMessage |
| 261 | switch { |
| 262 | case strings.HasPrefix(payload, "{"): |
| 263 | if err := json.Unmarshal([]byte(payload), &raw); err != nil { |
| 264 | return out, fmt.Errorf("malformed JSON args: %w", err) |
| 265 | } |
| 266 | // Accept the {"cmd","args"} envelope the model tends to emit (mirroring |
| 267 | // @context's shape) as well as flat JSON. Merge the nested args OVER any |
| 268 | // sibling top-level keys instead of replacing the map wholesale: a partial |
| 269 | // envelope like {"cmd":"flatten","repo":"…","args":{"format":"jsonl"}} |
| 270 | // must keep its source key rather than silently drop it (which surfaced as |
| 271 | // a misleading "source required"/"mutually exclusive" error and cost the |
| 272 | // agent a retry turn). The "cmd" verb is dropped — it is not a flatten flag. |
| 273 | if inner, ok := raw["args"]; ok { |
| 274 | var innerMap map[string]json.RawMessage |
| 275 | if err := json.Unmarshal(inner, &innerMap); err == nil { |
| 276 | delete(raw, "args") |
| 277 | delete(raw, "cmd") |
| 278 | for k, v := range innerMap { |
| 279 | raw[k] = v |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | default: |
| 284 | var jsonErr error |
| 285 | raw, jsonErr = docsFlattenArgvToMap(args) |
| 286 | if jsonErr != nil { |
| 287 | return out, jsonErr |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | out.Root = jsonString(raw, "root", "dir", "path") |
| 292 | out.Repo = jsonString(raw, "repo", "repoUrl") |
| 293 | parseDocsFlattenCrawlArgs(raw, &out) |
| 294 | if v := jsonString(raw, "branch"); v != "" { |
| 295 | out.Branch = v |
| 296 | } |
| 297 | out.Subdir = jsonString(raw, "subdir") |
| 298 | if v := strings.ToLower(jsonString(raw, "format")); v != "" { |
| 299 | out.Format = v |
| 300 | } |
| 301 | if v, ok := raw["maxChars"]; ok && len(v) > 0 { |
| 302 | out.MaxChars = jsonInt(raw, "maxChars") |
| 303 | } else if _, ok := raw["max-chars"]; ok { |
| 304 | out.MaxChars = jsonInt(raw, "max-chars") |
| 305 | } |
| 306 | out.Include = splitDocsFlattenCSV(jsonString(raw, "include")) |
| 307 | out.Exclude = splitDocsFlattenCSV(jsonString(raw, "exclude")) |
| 308 | if v, present := jsonBoolLookup(raw, "stripFrontMatter", "strip-front-matter"); present { |
| 309 | out.StripFrontMatter = v |
| 310 | } |
| 311 | out.Output = jsonString(raw, "output", "out") |
| 312 | if v := strings.ToLower(jsonString(raw, "kind")); v != "" { |
| 313 | out.Kind = v |
| 314 | } |