(sessionID, pattern, toolCallID string)
| 93 | } |
| 94 | |
| 95 | func (s Service) Search(sessionID, pattern, toolCallID string) ([]SearchMatch, security.DecisionRecord, error) { |
| 96 | meta, err := s.sessionMeta(sessionID) |
| 97 | if err != nil { |
| 98 | return nil, security.DecisionRecord{}, err |
| 99 | } |
| 100 | var matches []SearchMatch |
| 101 | err = filepath.Walk(meta.WorkspacePath, func(path string, info os.FileInfo, walkErr error) error { |
| 102 | if walkErr != nil { |
| 103 | return walkErr |
| 104 | } |
| 105 | if info.IsDir() || !info.Mode().IsRegular() { |
| 106 | return nil |
| 107 | } |
| 108 | body, err := os.ReadFile(path) |
| 109 | if err != nil { |
| 110 | return err |
| 111 | } |
| 112 | lines := strings.Split(string(body), "\n") |
| 113 | rel, _ := filepath.Rel(meta.WorkspacePath, path) |
| 114 | for i, line := range lines { |
| 115 | if strings.Contains(line, pattern) { |
| 116 | matches = append(matches, SearchMatch{Path: "/" + filepath.ToSlash(rel), Line: i + 1, Text: line}) |
| 117 | } |
| 118 | } |
| 119 | return nil |
| 120 | }) |
| 121 | if err != nil { |
| 122 | return nil, security.DecisionRecord{}, err |
| 123 | } |
| 124 | record, err := s.recordEvent(security.Event{ |
| 125 | Source: "computer_api", |
| 126 | EventType: "search", |
| 127 | RunID: meta.RunID, |
| 128 | SessionID: sessionID, |
| 129 | ToolCallID: ensureToolCallID(toolCallID), |
| 130 | Args: []string{pattern}, |
| 131 | }, map[string]any{ |
| 132 | "pattern": pattern, |
| 133 | "match_count": len(matches), |
| 134 | "result_ref": "search:" + ensureToolCallID(toolCallID), |
| 135 | }) |
| 136 | return matches, record, err |
| 137 | } |
| 138 | |
| 139 | func (s Service) ExportArtifact(sessionID, filePath, name, toolCallID string) (string, security.DecisionRecord, error) { |
| 140 | meta, err := s.sessionMeta(sessionID) |
no test coverage detected