LoadBootstrapContent loads all bootstrap files with mtime-based cache invalidation. Priority: workspace > global (workspace files override global).
()
| 48 | // LoadBootstrapContent loads all bootstrap files with mtime-based cache invalidation. |
| 49 | // Priority: workspace > global (workspace files override global). |
| 50 | func (bl *BootstrapLoader) LoadBootstrapContent() string { |
| 51 | var parts []string |
| 52 | |
| 53 | for _, filename := range BootstrapFiles { |
| 54 | content, ok := bl.LoadFile(filename) |
| 55 | if ok && strings.TrimSpace(content) != "" { |
| 56 | parts = append(parts, fmt.Sprintf("## %s\n\n%s", filename, content)) |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | if len(parts) == 0 { |
| 61 | return "" |
| 62 | } |
| 63 | content := strings.Join(parts, "\n\n---\n\n") |
| 64 | |
| 65 | // Neutralize blatant prompt-injection directives that may have been |
| 66 | // planted in a bootstrap file (e.g. a cloned repo's AGENTS.md) before |
| 67 | // the text reaches the model. Conservative, line-level — legitimate |
| 68 | // shell snippets in context files are left untouched (ScopeContext). |
| 69 | if threatscan.Enabled() { |
| 70 | if sanitized, blocked := threatscan.Sanitize(content, threatscan.ScopeContext); blocked > 0 { |
| 71 | bl.logger.Warn("threatscan: neutralized lines in bootstrap context", |
| 72 | zap.Int("blocked", blocked)) |
| 73 | content = sanitized |
| 74 | } |
| 75 | } |
| 76 | return content |
| 77 | } |
| 78 | |
| 79 | // LoadFile loads a single bootstrap file (workspace first, then global). |
| 80 | func (bl *BootstrapLoader) LoadFile(filename string) (string, bool) { |