mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-29 12:03:09 +00:00
chore: publish from main
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
# Edit Tutorial
|
||||
|
||||
A canvas extension that turns a set of code changes into an interactive lesson: the
|
||||
edits the agent made in the current session, or the changes in a commit (the last
|
||||
commit by default) when the agent made none. The lesson is a step-by-step walkthrough
|
||||
of each change, comprehension quizzes, and a hands-on exercise the learner finishes in
|
||||
the canvas in order to understand the updates to the source code.
|
||||
|
||||

|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Node.js 20.19 or newer** because the Copilot SDK requires `node ^20.19.0 || >=22.12.0`.
|
||||
- The GitHub Copilot app canvas / UI-extensions experiment enabled.
|
||||
|
||||
## Install
|
||||
|
||||
Drop this folder at `~/.copilot/extensions/edit-tutorial/` for user scope, or in a repository at
|
||||
`.github/extensions/edit-tutorial/` for project scope. Then install dependencies from inside the
|
||||
copied folder:
|
||||
|
||||
```sh
|
||||
# User scope
|
||||
cd ~/.copilot/extensions/edit-tutorial
|
||||
|
||||
# Or project scope, from the repository root
|
||||
cd .github/extensions/edit-tutorial
|
||||
|
||||
npm install
|
||||
```
|
||||
|
||||
Reload extensions in the GitHub Copilot app, then when updating a repository using the Copilot app,
|
||||
add a line like:
|
||||
|
||||
```text
|
||||
Start an edit tutorial for the update.
|
||||
```
|
||||
|
||||
at the end of the prompt to start the `edit-tutorial` canvas. To learn an existing
|
||||
change without the agent editing anything, ask on its own:
|
||||
|
||||
```text
|
||||
Start an edit tutorial from the last commit.
|
||||
```
|
||||
|
||||
## What It Does
|
||||
|
||||
- **Two sources**: the code edits the agent made in the current session, or the
|
||||
changes in a commit when there are no session edits. The most recent commit is the
|
||||
default; name any commit to learn that one instead.
|
||||
- **Lesson history**: each newly titled lesson joins a history of up to 10. When
|
||||
more than one exists, arrows under the progress counter let the learner flip
|
||||
between lessons, each keeping its own progress. Republishing the active lesson with
|
||||
the same title replaces it instead of adding a new one.
|
||||
- **Walkthrough**: one step per focused edit, each with the file, an explanation, a
|
||||
before/after code view with change highlighting, and an optional multiple-choice quiz.
|
||||
- **Exercise**: finishing the walkthrough unlocks a hands-on task that applies the same
|
||||
technique as the session's edits, but as a slight variation (a different function,
|
||||
module, or parameter values), so the learner writes the change themselves instead of
|
||||
rereading it.
|
||||
- **Completion**: local regex checks validate the attempt, hints reveal one at a time,
|
||||
a reference solution unlocks after repeated failed attempts, and the learner can send
|
||||
their code to the agent for a coaching review. Passing the checks, or an approving
|
||||
review, completes the lesson.
|
||||
- **Persistence**: lesson content and learner progress are saved to the session
|
||||
workspace, so reopening the canvas resumes where the learner left off. Each save
|
||||
also refreshes a read-only HTML snapshot of the rendered lesson, so the tutorial
|
||||
survives an app restart as a readable artifact instead of raw state data. All
|
||||
Edit Tutorial canvases open in one session share this same lesson state, so a
|
||||
second canvas is another view of the same lessons, not a separate copy.
|
||||
|
||||
For example, if the agent added retry-with-backoff logic to `fetchUser`, the lesson
|
||||
walks through that change and then asks the learner to apply the same pattern to
|
||||
`fetchOrders` with a different attempt cap and starting delay.
|
||||
|
||||
## Preserved Artifact
|
||||
|
||||
The live canvas is served by the extension process on a loopback port, so it cannot
|
||||
outlive the app. Two files are written to the session workspace on every save:
|
||||
|
||||
| File | Purpose |
|
||||
| --- | --- |
|
||||
| `files/edit-tutorial-state.json` | Machine state used to restore the live canvas on reopen |
|
||||
| `files/edit-tutorial-artifact.html` | Self-contained, read-only rendering of the lesson and progress |
|
||||
|
||||
After the app is closed and reopened, the conversation can preserve the HTML artifact
|
||||
in place of the live canvas: it renders the full walkthrough, quiz results, revealed
|
||||
hints, and the learner's exercise attempt, with no scripts, no token, and no server
|
||||
behind it. When the history holds several lessons, the artifact shows the active one
|
||||
and labels it ("Lesson 2 of 3"). The artifact also embeds the state document, lesson
|
||||
history included, in a non-executing JSON block, so the lessons can be rebuilt from
|
||||
the artifact alone if the state file is ever lost.
|
||||
|
||||
That rebuild is automatic. A chat resumes the same session, so the canvas restores
|
||||
from the state file directly. A project reopens into a fresh session whose workspace
|
||||
holds only what was preserved from the conversation; when the canvas opens and finds
|
||||
no state file, the extension scans the workspace for a preserved artifact (under its
|
||||
original name or a copied one) and restores the lessons and progress from its
|
||||
embedded state block, so the canvas survives wherever the artifact does.
|
||||
|
||||
Reopening the canvas is automatic. In a session attached to a repository, the app
|
||||
brings the workspace files back after a restart but does not reopen the canvas on
|
||||
its own. Shortly after the session starts, the extension checks a few times whether
|
||||
a lesson is stored while no canvas has opened, waiting out the app still restoring
|
||||
files, and then sends the session a reopen request itself, the same message a
|
||||
stranded learner would type by hand, at most one message per session start. It also hands
|
||||
the agent the same instruction as context at session start and on each prompt. A
|
||||
canvas the learner closed on purpose stays closed, and if the canvas still does not
|
||||
come back, the manual paths below always work.
|
||||
|
||||
### If the canvas does not come back after a restart
|
||||
|
||||
Three manual paths bring the lesson back immediately in a repository session, best
|
||||
first:
|
||||
|
||||
- **Reopen from the app menu**: click the "+" icon, choose "Extensions", then
|
||||
"Edit Tutorial". The canvas opens and restores the stored lessons and progress
|
||||
from disk on its own. This is the fastest path and needs no agent turn.
|
||||
- **Continue by asking**: ask Copilot to "reopen the edit-tutorial canvas". Opening
|
||||
the canvas restores everything the same way; nothing is lost by the canvas having
|
||||
been closed, and asking does not rebuild or reset the lesson.
|
||||
- **Read it now**: in the session's Files panel, open `edit-tutorial-artifact.html`
|
||||
and choose "Open in browser". That page is the preserved lesson, progress
|
||||
included, as a read-only snapshot, and it tells you how to resume.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Let the agent make a change to your code, then open the Edit Tutorial canvas and
|
||||
click "Build my tutorial" (or just ask: "teach me what you changed"). If the agent
|
||||
made no edits in the session, the lesson is built from the last commit instead;
|
||||
you can also ask for that directly: "teach me the last commit".
|
||||
2. The agent reviews the session's edits, or the commit's changes, and publishes the
|
||||
lesson to the canvas with the `set_tutorial` action.
|
||||
3. Work through the steps, answer the quizzes, and finish the exercise in the canvas
|
||||
editor.
|
||||
|
||||
## Canvas Actions
|
||||
|
||||
| Action | Purpose |
|
||||
| --- | --- |
|
||||
| `set_tutorial` | Publish a lesson (title, summary, source, steps, exercise); a new title adds to the lesson history, the active title replaces |
|
||||
| `get_progress` | Read the learner's step progress and current exercise attempt |
|
||||
| `approve_exercise` | Mark the exercise complete after a successful review |
|
||||
| `reset_progress` | Restart the current lesson without changing its content |
|
||||
|
||||
### Example `set_tutorial` Payload
|
||||
|
||||
Quizzes are optional per step. Each `solutionChecks` entry is a JavaScript regular
|
||||
expression the learner's attempt must match; its `hint` is shown when the check fails.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Show Details</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Retry with exponential",
|
||||
"summary": "The API client now retries transient failures with exponential.",
|
||||
"source": "Commit a1b2c3d: retry transient API failures",
|
||||
"steps": [
|
||||
{
|
||||
"file": "src/api/client.js",
|
||||
"heading": "Wrap the request in a retry loop",
|
||||
"explanation": "The single request call becomes a bounded loop.",
|
||||
"before": "const res = await get(\"/users/\" + id);",
|
||||
"after": "for (let attempt = 1; attempt <= maxAttempts; attempt++) { ... }",
|
||||
"quiz": {
|
||||
"question": "Why bound the loop?",
|
||||
"options": ["To avoid retrying forever", "To speed up requests"],
|
||||
"answerIndex": 0,
|
||||
"why": "A bounded loop guarantees the call eventually settles."
|
||||
}
|
||||
}
|
||||
],
|
||||
"exercise": {
|
||||
"heading": "Your turn: retry the orders endpoint",
|
||||
"brief": "Apply the same pattern to fetchOrders, capped at 5 attempts.",
|
||||
"file": "src/api/orders.js",
|
||||
"starterCode": "async function fetchOrders(customerId) { ... }",
|
||||
"hints": ["Start from the loop shape used in fetchUser."],
|
||||
"solutionChecks": [
|
||||
{ "pattern": "maxAttempts\\s*=\\s*5", "hint": "Cap the attempts at 5" }
|
||||
],
|
||||
"solution": "async function fetchOrders(customerId) { ... }"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Distribution
|
||||
|
||||
This extension is shipped through the `edit-tutorial` plugin:
|
||||
|
||||
```bash
|
||||
copilot plugin install edit-tutorial@awesome-copilot
|
||||
```
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "edit-tutorial",
|
||||
"version": 1
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "canvas-edit-tutorial",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "extension.mjs",
|
||||
"description": "GitHub Copilot canvas extension that turns agent code edits, or a commit's changes, into an interactive lesson with a walkthrough and a hands-on variation exercise.",
|
||||
"dependencies": {
|
||||
"@github/copilot-sdk": "latest"
|
||||
},
|
||||
"keywords": [
|
||||
"agent-edits",
|
||||
"code-walkthrough",
|
||||
"commit-walkthrough",
|
||||
"guided-exercise",
|
||||
"interactive-tutorial",
|
||||
"learning",
|
||||
"onboarding"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user