Skip to content

feat(figma): thread Figma through CLI and orchestrator (Phase D — T2F.8, T2F.9)#42

Open
canonical-muhammadbassiony wants to merge 3 commits into
feat/figma-phase-c-mappingfrom
feat/figma-phase-d-cli
Open

feat(figma): thread Figma through CLI and orchestrator (Phase D — T2F.8, T2F.9)#42
canonical-muhammadbassiony wants to merge 3 commits into
feat/figma-phase-c-mappingfrom
feat/figma-phase-d-cli

Conversation

@canonical-muhammadbassiony

Copy link
Copy Markdown
Collaborator

Summary

Threads Figma integration through the CLI and orchestrator, completing Phase D of spec 002.

Tasks Implemented

  • T2F.8: Added --figma-url flag to cmd/bauer/main.go, wired into CLIFlags.FigmaURL. The orchestrator forks on cfg.FigmaURL != "": the figma-aware path calls generateChunksWithFigma() which fetches design data via sources.FetchFigma, runs mapping.Resolver.Build, persists figma artifacts, and generates prompts via engine.RenderChunksFromResolved.
  • T2F.9: Added optional MCP guidance block to prompts. FigmaURL field added to figmaChunkContext (with json:"-"), and figma-context.md has a {{if .FigmaURL}} conditional section with instructions for AI agents that have MCP access.

Files Changed

  • cmd/bauer/main.go--figma-url flag, wired through FlagsSource
  • internal/orchestrator/orchestrator.gogenerateChunksWithFigma() method; Execute forks on FigmaURL
  • internal/prompt/engine.goFigmaURL in context; RenderChunksFromResolved() method
  • internal/prompt/templates/figma-context.md — MCP guidance block ({{if .FigmaURL}})

Part of the Bauer v2 stacked PR series (Branch 7 of 12).

…uidance in prompts

T2F.8: cmd/bauer --figma-url flag wired through CLIFlags and Config
T2F.8: orchestrator.Execute forks on cfg.FigmaURL for figma-aware prompt generation
T2F.8: generateChunksWithFigma fetches design, runs mapping.Resolver, writes artifacts
T2F.9: figmaChunkContext.FigmaURL field enables MCP guidance block in template
T2F.9: figma-context.md optional MCP section renders when FigmaURL is set
T2F.9: Engine.RenderChunksFromResolved writes figma-aware prompt files to disk

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Threads the optional Figma integration end-to-end so a supplied --figma-url can drive design-aware prompt generation via the orchestrator, and adds an optional MCP guidance section in the Figma prompt template.

Changes:

  • Add a --figma-url CLI flag and pass it through config into orchestration.
  • Fork orchestrator prompt generation to a Figma-aware path that fetches/normalizes Figma data, builds mappings, persists artifacts, and renders prompts from resolved chunks.
  • Extend prompt rendering/template context to optionally include a Figma MCP guidance block when a Figma URL is present.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
cmd/bauer/main.go Adds --figma-url flag and updates CLI help text / config wiring.
internal/orchestrator/orchestrator.go Adds Figma-aware prompt generation path (generateChunksWithFigma) and switches Execute based on cfg.FigmaURL.
internal/prompt/engine.go Threads FigmaURL into the figma template context and adds RenderChunksFromResolved helper.
internal/prompt/templates/figma-context.md Adds conditional MCP guidance block rendered when .FigmaURL is set.
docs/implementation-log.md Updates implementation log entry for this phase.
Comments suppressed due to low confidence (1)

internal/orchestrator/orchestrator.go:364

  • executeAgentChunks has a formatting issue (func executeAgentChunks( ctx ...) that should be cleaned up; it looks like a gofmt regression and may fail golangci-lint formatting checks. Please run gofmt (or fix the signature formatting) before merging.
// executeAgentChunks executes each chunk via the agent and returns outputs.
func executeAgentChunks(	ctx context.Context,
	chunks []prompt.ChunkResult,
	cfg *config.Config,
	a agent.Agent,
) ([]ChunkOutput, time.Duration, error) {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/bauer/main.go Outdated
Comment on lines +34 to +47
@@ -47,8 +44,7 @@ func main() {
fmt.Fprintf(os.Stderr, "\tBAUER_ARTIFACTS_DIR Override for --artifacts-dir\n")
fmt.Fprintf(os.Stderr, "\tBAUER_BRANCH_PREFIX Override for --branch-prefix\n")
fmt.Fprintf(os.Stderr, "\tBAUER_GITHUB_REPO Override for --github-repo\n")
fmt.Fprintf(os.Stderr, "\n")
}
fmt.Fprintf(os.Stderr, "\tBAUER_FIGMA_TOKEN Figma API token (required when --figma-url is supplied)\n")
Comment on lines +306 to +310
slog.Warn("Failed to create screenshots dir, proceeding without screenshots",
slog.String("error", err.Error()))
screenshotDir = ""
}
}
Comment thread internal/orchestrator/orchestrator.go Outdated
@@ -273,8 +282,82 @@ func (o *DefaultOrchestrator) Execute(ctx context.Context, cfg *config.Config) (
}

// executeAgentChunks executes each chunk via the agent and returns outputs.
Comment thread internal/prompt/engine.go Outdated
Comment on lines +350 to +382
docTitle, suggestedURL, figmaURL string,
chunks []mapping.ResolvedChunk,
chunkSize int,
outputDir string,
) ([]ChunkResult, error) {
if err := os.MkdirAll(outputDir, 0755); err != nil {
return nil, fmt.Errorf("creating output directory %q: %w", outputDir, err)
}

promptDatas, err := e.GenerateChunksFromResolved(docTitle, suggestedURL, figmaURL, chunks, chunkSize)
if err != nil {
return nil, err
}

results := make([]ChunkResult, len(promptDatas))
for i, pd := range promptDatas {
content, err := e.RenderChunk(pd)
if err != nil {
return nil, fmt.Errorf("rendering chunk %d: %w", i+1, err)
}
fname := fmt.Sprintf("chunk-%d-of-%d.md", pd.ChunkNumber, pd.TotalChunks)
fpath := filepath.Join(outputDir, fname)
if err := os.WriteFile(fpath, []byte(content), 0644); err != nil {
return nil, fmt.Errorf("writing chunk %d to file: %w", i+1, err)
}
results[i] = ChunkResult{
ChunkNumber: pd.ChunkNumber,
Content: content,
Filename: fpath,
LocationCount: pd.LocationCount,
}
}
return results, nil
Comment thread internal/prompt/engine.go Outdated
Comment on lines +349 to +383
func (e *Engine) RenderChunksFromResolved(
docTitle, suggestedURL, figmaURL string,
chunks []mapping.ResolvedChunk,
chunkSize int,
outputDir string,
) ([]ChunkResult, error) {
if err := os.MkdirAll(outputDir, 0755); err != nil {
return nil, fmt.Errorf("creating output directory %q: %w", outputDir, err)
}

promptDatas, err := e.GenerateChunksFromResolved(docTitle, suggestedURL, figmaURL, chunks, chunkSize)
if err != nil {
return nil, err
}

results := make([]ChunkResult, len(promptDatas))
for i, pd := range promptDatas {
content, err := e.RenderChunk(pd)
if err != nil {
return nil, fmt.Errorf("rendering chunk %d: %w", i+1, err)
}
fname := fmt.Sprintf("chunk-%d-of-%d.md", pd.ChunkNumber, pd.TotalChunks)
fpath := filepath.Join(outputDir, fname)
if err := os.WriteFile(fpath, []byte(content), 0644); err != nil {
return nil, fmt.Errorf("writing chunk %d to file: %w", i+1, err)
}
results[i] = ChunkResult{
ChunkNumber: pd.ChunkNumber,
Content: content,
Filename: fpath,
LocationCount: pd.LocationCount,
}
}
return results, nil
} No newline at end of file

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — RenderChunksFromResolved should have unit test coverage. Tracking for a follow-up; out of scope for this PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 10 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

cmd/bauer/main.go:42

  • The usage banner was changed to Usage: <cmd> [flags], but --doc-id (or BAUER_DOC_ID) is still required and Config.Validate() will fail without it. Consider restoring a usage line that clearly indicates the required --doc-id <id> to avoid confusing users.
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Flags:\n\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nEnvironment variables:\n\n")
		fmt.Fprintf(os.Stderr, "\tBAUER_DOC_ID                    Override for --doc-id\n")
		fmt.Fprintf(os.Stderr, "\tBAUER_CREDENTIALS_PATH          Override for --credentials\n")

Comment thread cmd/bauer/main.go
Comment on lines 33 to 51
@@ -47,7 +47,7 @@ func main() {
fmt.Fprintf(os.Stderr, "\tBAUER_ARTIFACTS_DIR Override for --artifacts-dir\n")
fmt.Fprintf(os.Stderr, "\tBAUER_BRANCH_PREFIX Override for --branch-prefix\n")
fmt.Fprintf(os.Stderr, "\tBAUER_GITHUB_REPO Override for --github-repo\n")
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "\tBAUER_FIGMA_TOKEN Figma API token (required when --figma-url is supplied)\n")
}
figmaRef, err := figma.ParseLink(cfg.FigmaURL)
if err != nil {
return nil, fmt.Errorf("invalid figma URL %q: %w", cfg.FigmaURL, err)
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a known limitation. When a Figma URL has no node-id, FetchFigma still proceeds (fetches file-level metadata and comments) but produces zero anchors. The orchestrator continues without Figma anchor context (a warning is logged). Full whole-file node enumeration is planned but intentionally deferred; the current behavior is graceful degradation, not a failure path.

Comment on lines +300 to +317
// Determine screenshot directory (inside the artifact run when available).
screenshotDir := ""
if runID != "" {
screenshotDir, err = o.arts.EnsureScreenshotsDir(runID)
if err != nil {
slog.Warn("Failed to create screenshots dir, proceeding without screenshots",
slog.String("error", err.Error()))
screenshotDir = ""
}
}

if screenshotDir == "" {
slog.Warn("Screenshot directory unavailable, skipping screenshot download")
}

slog.Info("Fetching Figma design data", slog.String("figma_url", cfg.FigmaURL))
design, err := o.sources.FetchFigma(ctx, figmaClient, figmaRef, screenshotDir)
if err != nil {

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 11 changed files in this pull request and generated 2 comments.

Comment thread internal/prompt/engine.go
Comment on lines 144 to +150
// Append figma context section when design data is present
if data.FigmaContextJSON != "" {
var ctx figmaChunkContext
if err := json.Unmarshal([]byte(data.FigmaContextJSON), &ctx); err != nil {
return "", fmt.Errorf("parsing figma context JSON: %w", err)
}
ctx.FigmaURL = data.FigmaURL
Comment thread internal/github/pr.go
@@ -77,7 +77,7 @@ func CreatePR(owner, repo string, opts CreatePROptions) (string, error) {
} else {
logger.Debug("GH_TOKEN is set for PR creation", "token_prefix", ghToken[:10])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants