Function bodies 590 total
logformat.statusIcon function · go · L332-L343 (12 LOC)cli/internal/agents/logformat/formatter.go
func statusIcon(status string) string {
switch status {
case "completed":
return "[x]"
case "in_progress":
return "[>]"
case "pending":
return "[ ]"
default:
return "[?]"
}
}logformat.formatDuration function · go · L345-L356 (12 LOC)cli/internal/agents/logformat/formatter.go
func formatDuration(ms int64) string {
d := time.Duration(ms) * time.Millisecond
if d < time.Second {
return fmt.Sprintf("%dms", ms)
}
if d < time.Minute {
return fmt.Sprintf("%.1fs", d.Seconds())
}
minutes := int(d.Minutes())
seconds := int(d.Seconds()) % 60
return fmt.Sprintf("%dm %ds", minutes, seconds)
}logformat.ParseEvent function · go · L135-L141 (7 LOC)cli/internal/agents/logformat/types.go
func ParseEvent(line []byte) (*Event, error) {
var event Event
if err := json.Unmarshal(line, &event); err != nil {
return nil, fmt.Errorf("failed to parse event: %w", err)
}
return &event, nil
}logformat.Message.ParseContentBlocks method · go · L145-L163 (19 LOC)cli/internal/agents/logformat/types.go
func (m *Message) ParseContentBlocks() ([]ContentBlock, error) {
if m == nil || len(m.Content) == 0 {
return nil, nil
}
// Try parsing as array first (most common)
var blocks []ContentBlock
if err := json.Unmarshal(m.Content, &blocks); err == nil {
return blocks, nil
}
// Try parsing as string (less common)
var text string
if err := json.Unmarshal(m.Content, &text); err == nil {
return []ContentBlock{{Type: "text", Text: text}}, nil
}
return nil, nil
}logformat.ContentBlock.ParseToolInput method · go · L166-L175 (10 LOC)cli/internal/agents/logformat/types.go
func (cb *ContentBlock) ParseToolInput() (*ToolInput, error) {
if len(cb.Input) == 0 {
return nil, nil
}
var input ToolInput
if err := json.Unmarshal(cb.Input, &input); err != nil {
return nil, fmt.Errorf("failed to parse tool input: %w", err)
}
return &input, nil
}logformat.NewFormattingWriter function · go · L23-L28 (6 LOC)cli/internal/agents/logformat/writer.go
func NewFormattingWriter(output io.Writer) *FormattingWriter {
return &FormattingWriter{
output: output,
formatter: NewFormatter(),
}
}logformat.NewFormattingWriterWithFormatter function · go · L31-L36 (6 LOC)cli/internal/agents/logformat/writer.go
func NewFormattingWriterWithFormatter(output io.Writer, formatter *Formatter) *FormattingWriter {
return &FormattingWriter{
output: output,
formatter: formatter,
}
}Repobility — same analyzer, your code, free for public repos · /scan/
logformat.FormattingWriter.Write method · go · L40-L64 (25 LOC)cli/internal/agents/logformat/writer.go
func (w *FormattingWriter) Write(p []byte) (n int, err error) {
w.mu.Lock()
defer w.mu.Unlock()
// Add to buffer
w.buffer.Write(p)
// Process complete lines
for {
line, err := w.buffer.ReadBytes('\n')
if errors.Is(err, io.EOF) {
// Incomplete line, put it back
w.buffer.Write(line)
break
}
if err != nil {
return len(p), err
}
// Parse and format the line
w.processLine(line)
}
return len(p), nil
}logformat.FormattingWriter.Flush method · go · L67-L76 (10 LOC)cli/internal/agents/logformat/writer.go
func (w *FormattingWriter) Flush() error {
w.mu.Lock()
defer w.mu.Unlock()
if w.buffer.Len() > 0 {
w.processLine(w.buffer.Bytes())
w.buffer.Reset()
}
return nil
}logformat.FormattingWriter.processLine method · go · L78-L94 (17 LOC)cli/internal/agents/logformat/writer.go
func (w *FormattingWriter) processLine(line []byte) {
line = bytes.TrimSpace(line)
if len(line) == 0 {
return
}
event, err := ParseEvent(line)
if err != nil {
// Not valid JSON, skip silently
return
}
formatted := w.formatter.Format(event)
if formatted != "" {
_, _ = w.output.Write([]byte(formatted))
}
}logformat.FormatFile function · go · L98-L130 (33 LOC)cli/internal/agents/logformat/writer.go
func FormatFile(input io.Reader, output io.Writer) error {
formatter := NewFormatter()
scanner := bufio.NewScanner(input)
// Handle very long lines
const maxLineSize = 10 * 1024 * 1024 // 10MB
buf := make([]byte, maxLineSize)
scanner.Buffer(buf, maxLineSize)
for scanner.Scan() {
line := scanner.Bytes()
if len(line) == 0 {
continue
}
event, err := ParseEvent(line)
if err != nil {
continue
}
formatted := formatter.Format(event)
if formatted != "" {
if _, err := output.Write([]byte(formatted)); err != nil {
return fmt.Errorf("failed to write formatted output: %w", err)
}
}
}
if err := scanner.Err(); err != nil {
return fmt.Errorf("failed to scan input: %w", err)
}
return nil
}logformat.NewDualWriter function · go · L141-L146 (6 LOC)cli/internal/agents/logformat/writer.go
func NewDualWriter(raw io.Writer, formatted io.Writer) *DualWriter {
return &DualWriter{
raw: raw,
formatted: NewFormattingWriter(formatted),
}
}logformat.DualWriter.Write method · go · L149-L159 (11 LOC)cli/internal/agents/logformat/writer.go
func (w *DualWriter) Write(p []byte) (n int, err error) {
// Write to raw first
n, err = w.raw.Write(p)
if err != nil {
return n, fmt.Errorf("failed to write to raw output: %w", err)
}
// Then to formatted (ignore error as formatted output is best-effort)
_, _ = w.formatted.Write(p)
return n, nil
}agents.NewAgentRegistry function · go · L25-L36 (12 LOC)cli/internal/agents/registry.go
func NewAgentRegistry() *AgentRegistry {
r := &AgentRegistry{
agents: make(map[string]*Agent),
}
// Register all standard agents
for _, agent := range StandardAgents() {
r.Register(agent)
}
return r
}agents.AgentRegistry.Register method · go · L46-L52 (7 LOC)cli/internal/agents/registry.go
func (r *AgentRegistry) Register(agent *Agent) {
if _, exists := r.agents[agent.Name]; exists {
panic(fmt.Sprintf("agent already registered: %s", agent.Name))
}
r.agents[agent.Name] = agent
}Repobility · code-quality intelligence · https://repobility.com
agents.AgentRegistry.Get method · go · L63-L70 (8 LOC)cli/internal/agents/registry.go
func (r *AgentRegistry) Get(name string) (*Agent, error) {
agent, ok := r.agents[name]
if !ok {
return nil, fmt.Errorf("unknown agent: %s", name)
}
return agent, nil
}agents.AgentRegistry.List method · go · L80-L87 (8 LOC)cli/internal/agents/registry.go
func (r *AgentRegistry) List() []*Agent {
agents := make([]*Agent, 0, len(r.agents))
for _, agent := range r.agents {
agents = append(agents, agent)
}
return agents
}agents.LoadPrompt function · go · L18-L24 (7 LOC)cli/internal/agents/templates.go
func LoadPrompt(promptPath string) (string, error) {
data, err := fs.ReadFile(templatesFS, "templates/"+promptPath)
if err != nil {
return "", fmt.Errorf("failed to load prompt %s: %w", promptPath, err)
}
return string(data), nil
}cmdutil.GetArtifactByIndex function · go · L12-L17 (6 LOC)cli/internal/cmdutil/artifacts.go
func GetArtifactByIndex(artifacts []state.Artifact, index int) (*state.Artifact, error) {
if err := IndexInRange(len(artifacts), index); err != nil {
return nil, err
}
return &artifacts[index], nil
}cmdutil.UpdateArtifactByIndex function · go · L21-L27 (7 LOC)cli/internal/cmdutil/artifacts.go
func UpdateArtifactByIndex(artifacts *[]state.Artifact, index int, artifact state.Artifact) error {
if err := IndexInRange(len(*artifacts), index); err != nil {
return err
}
(*artifacts)[index] = artifact
return nil
}cmdutil.SetArtifactField function · go · L31-L36 (6 LOC)cli/internal/cmdutil/artifacts.go
func SetArtifactField(artifacts *[]state.Artifact, index int, fieldPath string, value string) error {
if err := IndexInRange(len(*artifacts), index); err != nil {
return err
}
return SetField(&(*artifacts)[index], fieldPath, value)
}cmdutil.FormatArtifactList function · go · L49-L62 (14 LOC)cli/internal/cmdutil/artifacts.go
func FormatArtifactList(artifacts []state.Artifact) string {
if len(artifacts) == 0 {
return "No artifacts found."
}
var sb strings.Builder
sb.WriteString("Artifacts:\n")
for i, artifact := range artifacts {
sb.WriteString(fmt.Sprintf("\n[%d] %s\n", i, FormatArtifact(artifact)))
}
return sb.String()
}cmdutil.FormatArtifact function · go · L66-L81 (16 LOC)cli/internal/cmdutil/artifacts.go
func FormatArtifact(artifact state.Artifact) string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("Type: %s\n", artifact.Type))
sb.WriteString(fmt.Sprintf(" Path: %s\n", artifact.Path))
sb.WriteString(fmt.Sprintf(" Approved: %t\n", artifact.Approved))
if len(artifact.Metadata) > 0 {
sb.WriteString(" Metadata:\n")
for key, value := range artifact.Metadata {
sb.WriteString(fmt.Sprintf(" %s: %v\n", key, value))
}
}
return sb.String()
}Repobility — the code-quality scanner for AI-generated software · https://repobility.com
cmdutil.IndexInRange function · go · L85-L90 (6 LOC)cli/internal/cmdutil/artifacts.go
func IndexInRange(length int, index int) error {
if index < 0 || index >= length {
return fmt.Errorf("index out of range: %d (valid range: 0-%d)", index, length-1)
}
return nil
}cmdutil.GetContext function · go · L21-L27 (7 LOC)cli/internal/cmdutil/context.go
func GetContext(ctx context.Context) *sow.Context {
c, ok := ctx.Value(sowContextKey).(*sow.Context)
if !ok {
panic("sow context not found in context")
}
return c
}cmdutil.RequireInitialized function · go · L31-L37 (7 LOC)cli/internal/cmdutil/context.go
func RequireInitialized(ctx context.Context) (*sow.Context, error) {
c := GetContext(ctx)
if !c.IsInitialized() {
return nil, sow.ErrNotInitialized
}
return c, nil
}cmdutil.LoadProject function · go · L46-L53 (8 LOC)cli/internal/cmdutil/context.go
func LoadProject(ctx context.Context, sowCtx *sow.Context) (*state.Project, error) {
backend := state.NewYAMLBackend(sowCtx.FS())
proj, err := state.Load(ctx, backend)
if err != nil {
return nil, fmt.Errorf("load project: %w", err)
}
return proj, nil
}cmdutil.SaveProject function · go · L57-L62 (6 LOC)cli/internal/cmdutil/context.go
func SaveProject(ctx context.Context, proj *state.Project) error {
if err := state.Save(ctx, proj); err != nil {
return fmt.Errorf("save project: %w", err)
}
return nil
}cmdutil.CreateProject function · go · L66-L73 (8 LOC)cli/internal/cmdutil/context.go
func CreateProject(ctx context.Context, sowCtx *sow.Context, opts state.CreateOpts) (*state.Project, error) {
backend := state.NewYAMLBackend(sowCtx.FS())
proj, err := state.Create(ctx, backend, opts)
if err != nil {
return nil, fmt.Errorf("create project: %w", err)
}
return proj, nil
}cmdutil.ParseFieldPath function · go · L14-L19 (6 LOC)cli/internal/cmdutil/fieldpath.go
func ParseFieldPath(path string) []string {
if path == "" {
return []string{""}
}
return strings.Split(path, ".")
}cmdutil.SetField function · go · L50-L73 (24 LOC)cli/internal/cmdutil/fieldpath.go
func SetField(target interface{}, fieldPath string, value string) error {
if target == nil {
return fmt.Errorf("cannot set field on nil target")
}
if fieldPath == "" {
return fmt.Errorf("field path cannot be empty")
}
segments := ParseFieldPath(fieldPath)
// Check for invalid "metadata" without subfield
if len(segments) == 1 && segments[0] == "metadata" {
return fmt.Errorf("invalid metadata path: must specify a key after 'metadata'")
}
// Handle metadata paths
if IsMetadataPath(segments) {
return setMetadataField(target, segments[1:], value)
}
// Handle direct fields
return setDirectField(target, segments[0], value)
}Powered by Repobility — scan your code at https://repobility.com
cmdutil.setDirectField function · go · L98-L132 (35 LOC)cli/internal/cmdutil/fieldpath.go
func setDirectField(target interface{}, fieldName string, value string) error {
v := reflect.ValueOf(target)
if v.Kind() != reflect.Ptr {
return fmt.Errorf("target must be a pointer")
}
if v.IsNil() {
return fmt.Errorf("cannot set field on nil target")
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return fmt.Errorf("target must be a struct pointer")
}
// Handle wrapped state types - look for embedded struct
if v.NumField() > 0 {
firstField := v.Field(0)
if firstField.Type().Kind() == reflect.Struct && firstField.Type().Name() != "" {
// Try the embedded struct
v = firstField
}
}
field := v.FieldByName(capitalizeFirst(fieldName))
if !field.IsValid() {
return fmt.Errorf("unknown field: %s", fieldName)
}
if !field.CanSet() {
return fmt.Errorf("cannot set field: %s", fieldName)
}
return setFieldValue(field, value)
}cmdutil.setMetadataField function · go · L163-L200 (38 LOC)cli/internal/cmdutil/fieldpath.go
func setMetadataField(target interface{}, segments []string, value string) error {
if len(segments) == 0 {
return fmt.Errorf("invalid metadata path: must have at least one key after 'metadata'")
}
// Get the metadata map
metadataField, err := getMetadataMap(target)
if err != nil {
return err
}
// Navigate/create nested structure
currentMap := metadataField
for i := 0; i < len(segments)-1; i++ {
key := segments[i]
nextVal, exists := currentMap[key]
if !exists {
// Create new nested map
newMap := make(map[string]interface{})
currentMap[key] = newMap
currentMap = newMap
} else {
// Try to use existing map
nextMap, ok := nextVal.(map[string]interface{})
if !ok {
return fmt.Errorf("metadata path conflict: %s is not a map", key)
}
currentMap = nextMap
}
}
// Set the final value with type conversion
finalKey := segments[len(segments)-1]
currentMap[finalKey] = ConvertValue(value)
return nil
}cmdutil.setFieldValue function · go · L283-L310 (28 LOC)cli/internal/cmdutil/fieldpath.go
func setFieldValue(field reflect.Value, value string) error {
converted := ConvertValue(value)
switch field.Kind() {
case reflect.Bool:
if b, ok := converted.(bool); ok {
field.SetBool(b)
} else {
return fmt.Errorf("cannot convert %v to bool", converted)
}
case reflect.Int, reflect.Int64:
if i, ok := converted.(int); ok {
field.SetInt(int64(i))
} else {
return fmt.Errorf("cannot convert %v to int", converted)
}
case reflect.String:
if s, ok := converted.(string); ok {
field.SetString(s)
} else {
return fmt.Errorf("cannot convert %v to string", converted)
}
default:
return fmt.Errorf("unsupported field type: %s", field.Kind())
}
return nil
}cmdutil.capitalizeFirst function · go · L314-L319 (6 LOC)cli/internal/cmdutil/fieldpath.go
func capitalizeFirst(s string) string {
if s == "" {
return ""
}
return strings.ToUpper(s[:1]) + s[1:]
}cmdutil.IsKnownField function · go · L330-L342 (13 LOC)cli/internal/cmdutil/fieldpath.go
func IsKnownField(typeName string, fieldName string) bool {
fields, ok := knownFields[typeName]
if !ok {
return false
}
for _, f := range fields {
if f == fieldName {
return true
}
}
return false
}cmdutil.GetTypeName function · go · L345-L364 (20 LOC)cli/internal/cmdutil/fieldpath.go
func GetTypeName(target interface{}) string {
v := reflect.ValueOf(target)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
// Check for wrapped state types
switch target.(type) {
case *state.Artifact, state.Artifact:
return "Artifact"
case *state.Task, state.Task:
return "Task"
case *state.Phase, state.Phase:
return "Phase"
default:
return t.Name()
}
}logging.LogEntry.Validate method · go · L37-L48 (12 LOC)cli/internal/logging/entry.go
func (e *LogEntry) Validate() error {
if e.AgentID == "" {
return fmt.Errorf("agent ID is required")
}
if e.Action == "" {
return fmt.Errorf("action is required")
}
if e.Result == "" {
return fmt.Errorf("result is required")
}
return nil
}logging.LogEntry.Format method · go · L51-L79 (29 LOC)cli/internal/logging/entry.go
func (e *LogEntry) Format() string {
var b []byte
// Front matter
b = append(b, "---\n"...)
b = append(b, fmt.Sprintf("timestamp: %s\n", e.Timestamp.Format("2006-01-02 15:04:05"))...)
b = append(b, fmt.Sprintf("agent: %s\n", e.AgentID)...)
b = append(b, fmt.Sprintf("action: %s\n", e.Action)...)
b = append(b, fmt.Sprintf("result: %s\n", e.Result)...)
// Optional files list
if len(e.Files) > 0 {
b = append(b, "files:\n"...)
for _, file := range e.Files {
b = append(b, fmt.Sprintf(" - %s\n", file)...)
}
}
b = append(b, "---\n"...)
// Optional notes section
if e.Notes != "" {
b = append(b, "\n"...)
b = append(b, e.Notes...)
b = append(b, "\n"...)
}
return string(b)
}Repobility — same analyzer, your code, free for public repos · /scan/
logging.AppendLog function · go · L36-L92 (57 LOC)cli/internal/logging/file.go
func AppendLog(fs interface{}, logPath string, entry *LogEntry) error {
// Validate entry
if err := entry.Validate(); err != nil {
return fmt.Errorf("invalid log entry: %w", err)
}
// Format the entry
formatted := entry.Format()
// Wrap filesystem if needed to match interface
var reader func(string) ([]byte, error)
var writer func(string, []byte) error
switch f := fs.(type) {
case FileSystem:
reader = f.ReadFile
writer = func(path string, data []byte) error {
return f.WriteFile(path, data)
}
case interface {
ReadFile(string) ([]byte, error)
WriteFile(string, []byte) error
}:
reader = f.ReadFile
writer = f.WriteFile
case interface {
ReadFile(string) ([]byte, error)
WriteFile(string, []byte, os.FileMode) error
}:
reader = f.ReadFile
writer = func(path string, data []byte) error {
return f.WriteFile(path, data, 0644)
}
default:
return fmt.Errorf("unsupported filesystem type")
}
// Read existing content (if any)
existing, err := readelogging.isNotExist function · go · L95-L101 (7 LOC)cli/internal/logging/file.go
func isNotExist(err error) bool {
if err == nil {
return false
}
// Check for core.ErrNotExist or os.ErrNotExist
return errors.Is(err, core.ErrNotExist) || os.IsNotExist(err)
}breakdown.NewBreakdownProjectConfig function · go · L33-L41 (9 LOC)cli/internal/projects/breakdown/breakdown.go
func NewBreakdownProjectConfig() *project.ProjectTypeConfig {
builder := project.NewProjectTypeConfigBuilder("breakdown")
builder = configurePhases(builder)
builder = configureTransitions(builder)
builder = configureEventDeterminers(builder)
builder = configurePrompts(builder)
builder = builder.WithInitializer(initializeBreakdownProject)
return builder.Build()
}breakdown.configurePhases function · go · L53-L62 (10 LOC)cli/internal/projects/breakdown/breakdown.go
func configurePhases(builder *project.ProjectTypeConfigBuilder) *project.ProjectTypeConfigBuilder {
return builder.
WithPhase("breakdown",
project.WithStartState(project.State(Discovery)),
project.WithEndState(project.State(Publishing)),
project.WithOutputs("discovery", "work_unit_spec"),
project.WithTasks(),
project.WithMetadataSchema(breakdownMetadataSchema),
)
}breakdown.configureTransitions function · go · L72-L121 (50 LOC)cli/internal/projects/breakdown/breakdown.go
func configureTransitions(builder *project.ProjectTypeConfigBuilder) *project.ProjectTypeConfigBuilder {
return builder.
// Set initial state to Discovery
SetInitialState(project.State(Discovery)).
// Transition 1: Discovery → Active (discovery complete)
AddTransition(
project.State(Discovery),
project.State(Active),
project.Event(EventBeginActive),
project.WithProjectGuard("discovery document approved", func(p *state.Project) bool {
return hasApprovedDiscoveryDocument(p)
}),
project.WithProjectOnEntry(func(p *state.Project) error {
// Update breakdown phase status to "active"
phase := p.Phases["breakdown"]
phase.Status = "active"
p.Phases["breakdown"] = phase
return nil
}),
).
// Transition 2: Active → Publishing (intra-phase transition)
AddTransition(
project.State(Active),
project.State(Publishing),
project.Event(EventBeginPublishing),
project.WithProjectGuard("all work units approved and dependencies valid", breakdown.configureEventDeterminers function · go · L131-L142 (12 LOC)cli/internal/projects/breakdown/breakdown.go
func configureEventDeterminers(builder *project.ProjectTypeConfigBuilder) *project.ProjectTypeConfigBuilder {
return builder.
OnAdvance(project.State(Discovery), func(_ *state.Project) (project.Event, error) {
return project.Event(EventBeginActive), nil
}).
OnAdvance(project.State(Active), func(_ *state.Project) (project.Event, error) {
return project.Event(EventBeginPublishing), nil
}).
OnAdvance(project.State(Publishing), func(_ *state.Project) (project.Event, error) {
return project.Event(EventCompleteBreakdown), nil
})
}breakdown.configurePrompts function · go · L147-L153 (7 LOC)cli/internal/projects/breakdown/breakdown.go
func configurePrompts(builder *project.ProjectTypeConfigBuilder) *project.ProjectTypeConfigBuilder {
return builder.
WithOrchestratorPrompt(generateOrchestratorPrompt).
WithPrompt(project.State(Discovery), generateDiscoveryPrompt).
WithPrompt(project.State(Active), generateActivePrompt).
WithPrompt(project.State(Publishing), generatePublishingPrompt)
}breakdown.initializeBreakdownProject function · go · L164-L188 (25 LOC)cli/internal/projects/breakdown/breakdown.go
func initializeBreakdownProject(p *state.Project, initialInputs map[string][]projschema.ArtifactState) error {
now := p.Created_at
// Get initial inputs for breakdown phase
inputs := []projschema.ArtifactState{}
if initialInputs != nil {
if phaseInputs, exists := initialInputs["breakdown"]; exists {
inputs = phaseInputs
}
}
// Create breakdown phase (starts in_progress, state machine starts in Discovery state)
p.Phases["breakdown"] = projschema.PhaseState{
Status: "in_progress",
Enabled: true,
Created_at: now,
Started_at: now,
Inputs: inputs,
Outputs: []projschema.ArtifactState{},
Tasks: []projschema.TaskState{},
Metadata: make(map[string]interface{}),
}
return nil
}Repobility · code-quality intelligence · https://repobility.com
breakdown.hasApprovedDiscoveryDocument function · go · L23-L37 (15 LOC)cli/internal/projects/breakdown/guards.go
func hasApprovedDiscoveryDocument(p *state.Project) bool {
phase, exists := p.Phases["breakdown"]
if !exists {
return false
}
// Check for approved discovery artifact
for _, artifact := range phase.Outputs {
if artifact.Type == "discovery" && artifact.Approved {
return true
}
}
return false
}breakdown.allWorkUnitsApproved function · go · L50-L72 (23 LOC)cli/internal/projects/breakdown/guards.go
func allWorkUnitsApproved(p *state.Project) bool {
phase, exists := p.Phases["breakdown"]
if !exists {
return false
}
if len(phase.Tasks) == 0 {
return false
}
hasCompleted := false
for _, task := range phase.Tasks {
if task.Status == "completed" {
hasCompleted = true
} else if task.Status != "abandoned" {
// Task is not completed or abandoned, so not all are resolved
return false
}
}
// Must have at least one completed task
return hasCompleted
}breakdown.extractTaskDependencies function · go · L76-L103 (28 LOC)cli/internal/projects/breakdown/guards.go
func extractTaskDependencies(task projschema.TaskState) []string {
if task.Metadata == nil {
return nil
}
depsRaw, ok := task.Metadata["dependencies"]
if !ok {
return nil
}
deps, ok := depsRaw.([]interface{})
if !ok {
return nil
}
depStrings := make([]string, 0, len(deps))
for _, d := range deps {
if depStr, ok := d.(string); ok {
depStrings = append(depStrings, depStr)
}
}
if len(depStrings) == 0 {
return nil
}
return depStrings
}