| 402 | } |
| 403 | |
| 404 | func loadConfigMap(path string) (map[string]any, error) { |
| 405 | var m1, m2 map[string]any |
| 406 | data, err := os.ReadFile(path) |
| 407 | if err != nil { |
| 408 | if os.IsNotExist(err) { |
| 409 | return m1, nil |
| 410 | } |
| 411 | return nil, fmt.Errorf("failed to read config: %w", err) |
| 412 | } |
| 413 | if err = json.Unmarshal(data, &m1); err != nil { |
| 414 | return nil, wrapJSONError(data, err, "config.json") |
| 415 | } |
| 416 | secPath := securityPath(path) |
| 417 | data, err = os.ReadFile(secPath) |
| 418 | if err != nil { |
| 419 | if os.IsNotExist(err) { |
| 420 | return m1, nil |
| 421 | } |
| 422 | return nil, fmt.Errorf("failed to read security config: %w", err) |
| 423 | } |
| 424 | if err = yaml.Unmarshal(data, &m2); err != nil { |
| 425 | return nil, fmt.Errorf("failed to parse security config: %w", err) |
| 426 | } |
| 427 | if m2["web"] != nil || m2["skills"] != nil { |
| 428 | m3 := make(map[string]any) |
| 429 | if m2["web"] != nil { |
| 430 | m3["web"] = m2["web"] |
| 431 | delete(m2, "web") |
| 432 | } |
| 433 | if m2["skills"] != nil { |
| 434 | m3["skills"] = m2["skills"] |
| 435 | delete(m2, "skills") |
| 436 | if m, ok := m3["skills"].(map[string]any); ok { |
| 437 | if m["clawhub"] != nil { |
| 438 | m["registries"] = map[string]any{"clawhub": m["clawhub"]} |
| 439 | delete(m, "clawhub") |
| 440 | } |
| 441 | if gh, ok := m["github"].(map[string]any); ok { |
| 442 | registries, _ := m["registries"].(map[string]any) |
| 443 | if registries == nil { |
| 444 | registries = map[string]any{} |
| 445 | } |
| 446 | githubRegistry := map[string]any{} |
| 447 | for k, v := range gh { |
| 448 | githubRegistry[k] = v |
| 449 | } |
| 450 | if token, ok := githubRegistry["token"]; ok { |
| 451 | githubRegistry["auth_token"] = token |
| 452 | } |
| 453 | registries["github"] = githubRegistry |
| 454 | m["registries"] = registries |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | m2["tools"] = m3 |
| 459 | } |
| 460 | |
| 461 | // Handle model_list merging specially: m1 has array format, m2 has map format |