@@ -182,9 +182,11 @@ func reconstructWorkflowFileFromMap(frontmatter map[string]any, markdown string)
182182}
183183
184184// processIncludesWithWorkflowSpec processes @include directives in content and replaces local file references
185- // with workflowspec format (owner/repo/path@sha) for all includes found in the package
186- func processIncludesWithWorkflowSpec (content string , workflow * WorkflowSpec , commitSHA , packagePath string , verbose bool ) (string , error ) {
187- importsLog .Printf ("Processing @include directives: repo=%s, sha=%s, package=%s" , workflow .RepoSlug , commitSHA , packagePath )
185+ // with workflowspec format (owner/repo/path@sha) for all includes found in the package.
186+ // If localWorkflowDir is non-empty, any relative import path whose file exists under that directory is
187+ // left as a local relative path rather than being rewritten to a cross-repo reference.
188+ func processIncludesWithWorkflowSpec (content string , workflow * WorkflowSpec , commitSHA , packagePath , localWorkflowDir string , verbose bool ) (string , error ) {
189+ importsLog .Printf ("Processing @include directives: repo=%s, sha=%s, package=%s, localWorkflowDir=%s" , workflow .RepoSlug , commitSHA , packagePath , localWorkflowDir )
188190 if verbose {
189191 fmt .Fprintln (os .Stderr , console .FormatVerboseMessage ("Processing @include directives to replace with workflowspec" ))
190192 }
@@ -211,6 +213,12 @@ func processIncludesWithWorkflowSpec(content string, workflow *WorkflowSpec, com
211213 isOptional := directive .IsOptional
212214 includePath := directive .Path
213215
216+ // Skip if it's already a workflowspec (owner/repo/path@sha format)
217+ if isWorkflowSpecFormat (includePath ) {
218+ result .WriteString (line + "\n " )
219+ continue
220+ }
221+
214222 // Handle section references (file.md#Section)
215223 var filePath , sectionName string
216224 if strings .Contains (includePath , "#" ) {
@@ -230,34 +238,43 @@ func processIncludesWithWorkflowSpec(content string, workflow *WorkflowSpec, com
230238 continue
231239 }
232240
233- // Check for cycle detection
234- if visited [filePath ] {
235- if verbose {
236- fmt .Fprintln (os .Stderr , console .FormatWarningMessage (fmt .Sprintf ("Cycle detected for include: %s, skipping" , filePath )))
241+ // Preserve relative {{#import}} paths whose files exist in the local workflow directory.
242+ if localWorkflowDir != "" && ! strings .HasPrefix (filePath , "/" ) {
243+ if isLocalFileForUpdate (localWorkflowDir , filePath ) {
244+ importsLog .Printf ("Include path exists locally, preserving: %s" , filePath )
245+ result .WriteString (line + "\n " )
246+ // Add file to queue for processing nested includes (first visit only)
247+ if ! visited [filePath ] {
248+ visited [filePath ] = true
249+ queue = append (queue , fileToProcess {path : filePath })
250+ }
251+ continue
237252 }
238- continue
239253 }
240254
241- // Mark as visited
242- visited [ filePath ] = true
255+ // Resolve the file path relative to the workflow file's directory
256+ resolvedPath := resolveImportPath ( filePath , workflow . WorkflowPath )
243257
244258 // Build workflowspec for this include
245- workflowSpec := buildWorkflowSpecRef (workflow .RepoSlug , filePath , commitSHA , workflow .Version )
259+ workflowSpec := buildWorkflowSpecRef (workflow .RepoSlug , resolvedPath , commitSHA , workflow .Version )
246260
247261 // Add section if present
248262 if sectionName != "" {
249263 workflowSpec += "#" + sectionName
250264 }
251265
252- // Write the updated @include directive
266+ // Write the updated @include directive (even for duplicate occurrences)
253267 if isOptional {
254268 result .WriteString ("{{#import? " + workflowSpec + "}}\n " )
255269 } else {
256270 result .WriteString ("{{#import " + workflowSpec + "}}\n " )
257271 }
258272
259- // Add file to queue for processing nested includes
260- queue = append (queue , fileToProcess {path : filePath })
273+ // Only enqueue for nested-include processing on the first visit to prevent cycles
274+ if ! visited [filePath ] {
275+ visited [filePath ] = true
276+ queue = append (queue , fileToProcess {path : filePath })
277+ }
261278 } else {
262279 // Regular line, pass through
263280 result .WriteString (line + "\n " )
@@ -360,7 +377,7 @@ func processIncludesInContent(content string, workflow *WorkflowSpec, commitSHA
360377 isOptional := directive .IsOptional
361378 includePath := directive .Path
362379
363- // Skip if it's already a workflowspec (contains repo/path format)
380+ // Skip if it's already a workflowspec (owner/ repo/path@sha format)
364381 if isWorkflowSpecFormat (includePath ) {
365382 result .WriteString (line + "\n " )
366383 continue
@@ -385,7 +402,7 @@ func processIncludesInContent(content string, workflow *WorkflowSpec, commitSHA
385402 continue
386403 }
387404
388- // Preserve relative @include paths whose files exist in the local workflow directory.
405+ // Preserve relative {{#import}} paths whose files exist in the local workflow directory.
389406 if localWorkflowDir != "" && ! strings .HasPrefix (filePath , "/" ) {
390407 if isLocalFileForUpdate (localWorkflowDir , filePath ) {
391408 importsLog .Printf ("Include path exists locally, preserving: %s" , filePath )
0 commit comments