From 8184dbac0c0db5d3cc1c9012738d9df45c315539 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:00:09 +0000 Subject: [PATCH 1/2] Implement code snippet wrapping Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- scripts/build-docs.test.js | 30 +++++++++++++++++++++++++ scripts/lib/docs.css | 45 +++++++++++++++++++++++++++++++++++++ scripts/lib/marked-setup.js | 42 +++++++++++++++++++++++++++++----- 3 files changed, 112 insertions(+), 5 deletions(-) diff --git a/scripts/build-docs.test.js b/scripts/build-docs.test.js index d389bbf7..e8f367af 100644 --- a/scripts/build-docs.test.js +++ b/scripts/build-docs.test.js @@ -22,6 +22,22 @@ function buildDocs() { }; } +function renderSnippet(markdown) { + return execFileSync( + process.execPath, + [ + "-e", + ` + const { marked } = require("marked"); + const { setupBasePlugins } = require("./scripts/lib/marked-setup"); + setupBasePlugins(); + process.stdout.write(marked.parse(${JSON.stringify(markdown)})); + `, + ], + { cwd: repoDir, encoding: "utf8" } + ); +} + test("workshop SPA renders a single document h1", () => { const { html } = buildDocs(); @@ -103,6 +119,20 @@ test("markdown, md, yaml, and yml code blocks use compact icon-only editor chrom assert.ok(css.includes("padding: 12px;"), "expected compact YAML code padding"); }); +test("code blocks wrap long lines without relying on mobile-only styles", () => { + const { css } = buildDocs(); + + assert.ok(css.includes(".markdown-body pre {\n position: relative;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}")); + assert.ok(css.includes(".markdown-body pre > code {\n font-size: 1em;\n white-space: inherit;\n}")); +}); + +test("code block headers can render filenames from fence metadata", () => { + const html = renderSnippet("```yaml .github/workflows/hello.yml\nname: Hello\n```\n\n```markdown title=\"README.md\"\n# Hello\n```"); + + assert.ok(html.includes('.github/workflows/hello.yml')); + assert.ok(html.includes('README.md')); +}); + test("rendered workshop images use GitHub-like rounded corners", () => { const { css } = buildDocs(); diff --git a/scripts/lib/docs.css b/scripts/lib/docs.css index d5ab6f9c..0fe055b2 100644 --- a/scripts/lib/docs.css +++ b/scripts/lib/docs.css @@ -550,9 +550,12 @@ html[data-color-mode="dark"] .workshop-nav-btn-secondary:focus-visible { /* Code block copy button */ .markdown-body pre { position: relative; + white-space: pre-wrap; + overflow-wrap: anywhere; } .markdown-body pre > code { font-size: 1em; + white-space: inherit; } .code-copy-btn { position: absolute; @@ -616,6 +619,7 @@ html[data-color-mode="dark"] .code-copy-btn:hover { display: flex; align-items: center; gap: 6px; + min-width: 0; padding: 8px 14px; background-color: #161b22; border-bottom: 1px solid #30363d; @@ -639,6 +643,20 @@ html[data-color-mode="dark"] .code-copy-btn:hover { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; } +.code-block-filename { + min-width: 0; + margin-left: auto; + overflow: hidden; + font-size: 11px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.terminal-bar .code-block-filename { + color: #8b949e; + font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; +} + .markdown-body .terminal-pre { margin: 0; padding: 16px; @@ -681,6 +699,7 @@ html[data-color-mode="dark"] .code-copy-btn:hover { display: flex; align-items: center; gap: 8px; + min-width: 0; padding: 8px 14px; background: linear-gradient(90deg, #271052, #3b1b6f); border-bottom: 1px solid #8957e5; @@ -706,6 +725,10 @@ html[data-color-mode="dark"] .code-copy-btn:hover { letter-spacing: 0.02em; } +.agent-prompt-bar .code-block-filename { + color: #c6a7ff; +} + .markdown-body .agent-prompt-pre { margin: 0; padding: 16px 16px 16px 20px; @@ -952,6 +975,7 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is display: flex; align-items: center; gap: 8px; + min-width: 0; padding: 8px 14px; background-color: var(--bgColor-muted, #f6f8fa); border-bottom: 1px solid var(--borderColor-muted, #d0d7de); @@ -964,6 +988,10 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is line-height: 1; } +.markdown-editor-bar .code-block-filename { + color: var(--fgColor-muted, #59636e); +} + .markdown-body .markdown-editor-pre { margin: 0; padding: 12px 12px 12px 16px; @@ -1004,6 +1032,9 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is html[data-color-mode="auto"] .markdown-editor-icon { color: #8b949e; } + html[data-color-mode="auto"] .markdown-editor-bar .code-block-filename { + color: #8b949e; + } html[data-color-mode="auto"] .markdown-body .markdown-editor-pre { background-color: #0d1117; box-shadow: inset 3px 0 #30363d; @@ -1032,6 +1063,9 @@ html[data-color-mode="dark"] .markdown-editor-bar { html[data-color-mode="dark"] .markdown-editor-icon { color: #8b949e; } +html[data-color-mode="dark"] .markdown-editor-bar .code-block-filename { + color: #8b949e; +} html[data-color-mode="dark"] .markdown-body .markdown-editor-pre { background-color: #0d1117; box-shadow: inset 3px 0 #30363d; @@ -1061,6 +1095,7 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover { display: flex; align-items: center; gap: 8px; + min-width: 0; padding: 8px 14px; background-color: var(--bgColor-muted, #f6f8fa); border-bottom: 1px solid var(--borderColor-muted, #d0d7de); @@ -1073,6 +1108,10 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover { line-height: 1; } +.yaml-editor-bar .code-block-filename { + color: var(--fgColor-muted, #59636e); +} + .markdown-body .yaml-editor-pre { margin: 0; padding: 12px; @@ -1112,6 +1151,9 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover { html[data-color-mode="auto"] .yaml-editor-icon { color: #8b949e; } + html[data-color-mode="auto"] .yaml-editor-bar .code-block-filename { + color: #8b949e; + } html[data-color-mode="auto"] .markdown-body .yaml-editor-pre { background-color: #0d1117; } @@ -1139,6 +1181,9 @@ html[data-color-mode="dark"] .yaml-editor-bar { html[data-color-mode="dark"] .yaml-editor-icon { color: #8b949e; } +html[data-color-mode="dark"] .yaml-editor-bar .code-block-filename { + color: #8b949e; +} html[data-color-mode="dark"] .markdown-body .yaml-editor-pre { background-color: #0d1117; } diff --git a/scripts/lib/marked-setup.js b/scripts/lib/marked-setup.js index 208fa403..cda56227 100644 --- a/scripts/lib/marked-setup.js +++ b/scripts/lib/marked-setup.js @@ -19,6 +19,34 @@ const slugger = new GithubSlugger(); const shellLangs = new Set(['bash', 'sh', 'shell', 'zsh']); const terminalOutputLangs = new Set(['console', 'output', 'plaintext', 'text']); +function extractCodeBlockFilename(meta = '') { + let normalizedMeta = meta.trim(); + if (!normalizedMeta) return ''; + + if (normalizedMeta.startsWith('{') && normalizedMeta.endsWith('}')) { + normalizedMeta = normalizedMeta.slice(1, -1).trim(); + } + + const keyedFilenameMatch = normalizedMeta.match( + /(?:^|\s)(?:file|filename|path|title)=(?:"([^"]+)"|'([^']+)'|(\S+))/ + ); + if (keyedFilenameMatch) { + return keyedFilenameMatch[1] || keyedFilenameMatch[2] || keyedFilenameMatch[3] || ''; + } + + return /\s|=/.test(normalizedMeta) ? '' : normalizedMeta; +} + +function parseCodeBlockInfo(lang = '') { + const info = lang.trim(); + const firstTokenMatch = info.match(/^\S*/); + const langKey = (firstTokenMatch?.[0] || '').toLowerCase(); + const meta = info.slice(firstTokenMatch?.[0]?.length || 0).trim(); + const filename = extractCodeBlockFilename(meta); + + return { langKey, filename }; +} + // Register the heading anchor, task-list item, alert, syntax-highlight, and // code-block renderer plugins. Call this once before processing any markdown. function setupBasePlugins() { @@ -88,22 +116,26 @@ function setupBasePlugins() { useNewRenderer: true, renderer: { code({ text, lang, escaped }) { - const langKey = (lang || '').match(/^\S*/)?.[0]?.toLowerCase() ?? ''; + const { langKey, filename } = parseCodeBlockInfo(lang || ''); const codeText = text.replace(/\n$/, '') + '\n'; const codeHtml = escaped ? codeText : escapeHtml(codeText); + const filenameHtml = filename + ? `${escapeHtml(filename)}` + : ''; if (langKey === 'prompt') { - return `
\n
Agent prompt
\n
${codeHtml}
\n
\n`; + return `
\n
Agent prompt${filenameHtml}
\n
${codeHtml}
\n
\n`; } if (langKey === 'markdown' || langKey === 'md') { - return `
\n
\n
${codeHtml}
\n
\n`; + return `
\n
${filenameHtml}
\n
${codeHtml}
\n
\n`; } if (langKey === 'yaml' || langKey === 'yml') { - return `
\n
\n
${codeHtml}
\n
\n`; + return `
\n
${filenameHtml}
\n
${codeHtml}
\n
\n`; } const terminalLabel = shellLangs.has(langKey) ? langKey : terminalOutputLangs.has(langKey) ? 'output' : ''; if (!terminalLabel) return false; const escapedLang = escapeHtml(langKey); - return `
\n\n
${codeHtml}
\n
\n`; + const terminalBarAria = filename ? '' : ' aria-hidden="true"'; + return `
\n
${terminalLabel}${filenameHtml}
\n
${codeHtml}
\n
\n`; }, }, }); From 85b434214e88008e17116246a91e2c1df1b8bfcd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:10:18 +0000 Subject: [PATCH 2/2] docs: document snippet filenames Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/guidelines.md | 3 +++ workshop/04-github-actions-intro.md | 7 +++---- workshop/07-your-first-workflow.md | 2 +- workshop/07d-confirm-model-access.md | 2 +- workshop/14b-pr-reviewer-workflow.md | 4 ++-- workshop/15-conditional-logic.md | 6 +++--- workshop/16-connect-data-source.md | 6 +++--- workshop/17-add-mcp-tools.md | 4 ++-- workshop/18-share-and-reuse.md | 2 +- workshop/19-research-driven-training-node.md | 2 +- workshop/20-persistent-memory.md | 4 ++-- workshop/21-inline-sub-agents.md | 4 ++-- workshop/22-error-handling-and-resilience.md | 6 +++--- workshop/23-ab-experiments.md | 8 ++++---- workshop/24-self-hosted-runners.md | 6 +++--- workshop/26-manage-costs-and-budgets.md | 2 +- workshop/27-evaluate-workflow-quality.md | 2 +- 17 files changed, 36 insertions(+), 34 deletions(-) diff --git a/.github/workflows/guidelines.md b/.github/workflows/guidelines.md index f827acfe..db8bbf95 100644 --- a/.github/workflows/guidelines.md +++ b/.github/workflows/guidelines.md @@ -229,6 +229,9 @@ Multi-line callout (summary + body): - Use ` ```text ` for terminal output that learners read but do not type (for example, expected command output or error messages). - Use ` ```yaml ` for standalone YAML configuration fragments, ` ```markdown ` for Markdown syntax examples, and ` ```html ` or ` ```xml ` for markup. - When showing an agentic workflow example that includes both frontmatter and prompt body, prefer a ` ```markdown ` block that shows the full Markdown+frontmatter file shape instead of isolating the frontmatter in a standalone ` ```yaml ` region. +- When a fenced snippet represents the contents of a file, add the filename after the language token so the rendered snippet chrome can surface it (for example, ` ```markdown .github/workflows/daily-status.md ` or ` ```yaml .github/workflows/daily-status.lock.yml `). +- Prefer the bare relative path form for filename metadata in workshop content. The renderer also supports keyed metadata such as `title=` or `file=`, but workshop pages should use the bare path consistently unless a page needs a more complex title. +- Match the filename extension to the snippet language (`.md` for `markdown`, `.yml`/`.yaml` for `yaml`, and so on), and keep the same filename across a page while the learner is still editing that same file. ## Enterprise user preference in design decisions diff --git a/workshop/04-github-actions-intro.md b/workshop/04-github-actions-intro.md index 275cfaea..90e50ac6 100644 --- a/workshop/04-github-actions-intro.md +++ b/workshop/04-github-actions-intro.md @@ -39,7 +39,7 @@ A GitHub Actions workflow is a YAML file in `.github/workflows/` that tells GitH Annotated example — each comment names the key term (this is a standard Actions workflow, not an agentic workflow): -```yaml +```yaml .github/workflows/hello-workflow.yml # Standard GitHub Actions workflow — not an agentic workflow name: Hello Workflow @@ -57,7 +57,7 @@ jobs: A **runner** is the machine GitHub provisions for each job — fresh and isolated for every run. -```markdown +```markdown .github/workflows/hello-workflow.md --- runs-on: ubuntu-latest # also: windows-latest, macos-latest --- @@ -84,7 +84,7 @@ The diagram below shows how the five key parts fit together in every workflow fi Before reading on, label each highlighted part of the workflow below with its type: `trigger`, `job`, `runner`, `step`, or `action`. -```yaml +```yaml .github/workflows/hello-workflow.yml on: [push] jobs: test: @@ -137,4 +137,3 @@ Open a real workflow file and find the three core building blocks — no termina **Next:** [What Are Agentic Workflows?](05-agentic-workflows-intro.md) - diff --git a/workshop/07-your-first-workflow.md b/workshop/07-your-first-workflow.md index 0f94368b..ab647d67 100644 --- a/workshop/07-your-first-workflow.md +++ b/workshop/07-your-first-workflow.md @@ -62,7 +62,7 @@ Review the agent's edit, then continue. Prefer this path over hand-editing each **What the agent created** — the generated file should look roughly like this: -```markdown +```markdown .github/workflows/daily-report-status.md --- name: Daily Report Status on: diff --git a/workshop/07d-confirm-model-access.md b/workshop/07d-confirm-model-access.md index 8cb45439..c4178e38 100644 --- a/workshop/07d-confirm-model-access.md +++ b/workshop/07d-confirm-model-access.md @@ -96,7 +96,7 @@ Use this path when the organization that owns the repository has centralized Cop 1. Ask your organization administrator to confirm centralized billing is enabled. 2. Open `daily-report-status.md` and confirm the `permissions:` block includes `copilot-requests: write`: -```markdown +```markdown .github/workflows/daily-report-status.md --- permissions: contents: read diff --git a/workshop/14b-pr-reviewer-workflow.md b/workshop/14b-pr-reviewer-workflow.md index 02d33096..2f55b701 100644 --- a/workshop/14b-pr-reviewer-workflow.md +++ b/workshop/14b-pr-reviewer-workflow.md @@ -48,7 +48,7 @@ Review the agent's diff before accepting it. The source should contain one paren The workflow frontmatter should follow this shape: -```markdown +```markdown .github/workflows/pr-reviewer.md --- on: pull_request: @@ -76,7 +76,7 @@ Notice that the agent job has no repository or pull request write permission. `c Near the bottom, look for the two reusable blocks: -```markdown +```markdown .github/workflows/pr-reviewer.md ## agent: `pr-reviewer` --- description: Reviews one pull request for actionable problems diff --git a/workshop/15-conditional-logic.md b/workshop/15-conditional-logic.md index 365c5a0d..71a1a7d4 100644 --- a/workshop/15-conditional-logic.md +++ b/workshop/15-conditional-logic.md @@ -47,7 +47,7 @@ The skill adds this step to the frontmatter `steps:` block and recompiles the lo Open your daily-status workflow file (e.g., `.github/workflows/daily-status.md`) and add the following block inside the YAML frontmatter under `steps:`: -```markdown +```markdown .github/workflows/daily-status.md --- steps: - name: Count recent commits @@ -64,7 +64,7 @@ After adding it, run `gh aw compile` to regenerate the lock file. Here is the step structure the skill will add: -```markdown +```markdown .github/workflows/daily-status.md --- steps: - name: Count recent commits @@ -89,7 +89,7 @@ This shell command uses `git log` with a `--since` time filter to list only comm In the same frontmatter block, add a top-level `if:` key at the same indentation level as `on:` and `steps:`: -```markdown +```markdown .github/workflows/daily-status.md --- if: steps.recent.outputs.commit_count != '0' --- diff --git a/workshop/16-connect-data-source.md b/workshop/16-connect-data-source.md index a478a210..dabe317f 100644 --- a/workshop/16-connect-data-source.md +++ b/workshop/16-connect-data-source.md @@ -57,7 +57,7 @@ Here is what the first step looks like — the skill will add this for you: First, fetch the recent commit log: -```markdown +```markdown .github/workflows/daily-status.md - name: Fetch recent commits id: recent # step ID — referenced as steps.recent.outputs.… run: | @@ -75,7 +75,7 @@ First, fetch the recent commit log: Next, add a step to fetch open issues: -```markdown +```markdown .github/workflows/daily-status.md - name: Fetch open issues id: issues # step ID — referenced as steps.issues.outputs.… run: | @@ -101,7 +101,7 @@ Next, add a step to fetch open issues: The AI prompt lives in the Markdown body after the frontmatter. Update that section so it uses the step outputs: -```markdown +```markdown .github/workflows/daily-status.md --- # … your existing frontmatter with the two new steps … --- diff --git a/workshop/17-add-mcp-tools.md b/workshop/17-add-mcp-tools.md index a58a27e1..fac81dfa 100644 --- a/workshop/17-add-mcp-tools.md +++ b/workshop/17-add-mcp-tools.md @@ -56,7 +56,7 @@ The skill adds the `tools:` block and updates the brief. Review the diff before Here is the `tools:` block the skill will add: -```markdown +```markdown .github/workflows/daily-status.md --- name: Daily Status Report on: @@ -99,7 +99,7 @@ Open your daily-status workflow file (`.github/workflows/daily-status.md`) and f Below the frontmatter, update the task brief to tell the agent it can use the MCP tools: -```markdown +```markdown .github/workflows/daily-status.md You have access to GitHub tools via MCP. Use them to: 1. Fetch the last 5 commits on the default branch. 2. List all open issues labelled `bug`. diff --git a/workshop/18-share-and-reuse.md b/workshop/18-share-and-reuse.md index a13573c8..b9a0971d 100644 --- a/workshop/18-share-and-reuse.md +++ b/workshop/18-share-and-reuse.md @@ -74,7 +74,7 @@ Your teammate runs this inside their repository. `gh aw add` copies the Markdown Add a short comment at the top of your workflow's Markdown task brief so users know what to customise: -```markdown +```markdown .github/workflows/daily-status.md ``` diff --git a/workshop/19-research-driven-training-node.md b/workshop/19-research-driven-training-node.md index bc218866..69fed6a1 100644 --- a/workshop/19-research-driven-training-node.md +++ b/workshop/19-research-driven-training-node.md @@ -49,7 +49,7 @@ Write a one-paragraph node scope and list the exact [artifacts](https://github.g Add XML comments to preserve reasoning without interrupting learner flow: -```markdown +```markdown workshop/28-safe-outputs-selection.md