Repository navigation
fix(plugin): recover publishing after local-change checks fail - #45
Merged
Merged
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
…h-components-skill
The canvas showed a pending publish as active publishing until a push appeared or ten minutes passed, even when Copilot stopped without pushing. The Publish button now says "Waiting for Copilot" while the request is unacknowledged, and a guarded report_publish_result canvas action lets the agent mark the request blocked, canceled, or failed. The report must come from the requesting canvas with the unchanged target and mode, and is rejected once push evidence is observed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
Local agent skills under .github/skills, .agents/skills and .claude/skills no longer count as uncommitted prototype changes, so a fully committed prototype publishes without the dialog. The dialog lists the remaining changed paths and notes that local skills stay uncommitted. When commit mode finds no task-related changes, the skill publishes the verified current commit instead of stopping. A failed publish request now clears when the same checkout observes a new push of the current HEAD, so workflow and Build evidence replace an obsolete failure. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
Stream Git status and retain only displayed paths. Offer retry or verified committed-only publishing when inspection fails, without permitting commits from unchecked state. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b38cbd43-5aa9-4803-8aa5-3d1ba9eef40e # Conflicts: # .github/extensions/replica-prototype/README.md # .github/extensions/replica-prototype/assets/renderer.js # .github/extensions/replica-prototype/marketplace.test.mjs # .github/extensions/replica-prototype/plugin.json # .github/extensions/replica-prototype/register-prototype-canvas/index.mjs # .github/extensions/replica-prototype/register-prototype-canvas/index.test.mjs # .github/extensions/replica-prototype/report-publish-result/index.mjs # .github/extensions/replica-prototype/report-publish-result/index.test.mjs # hub/docs/prototype-canvas.md
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved publishing-state and timeout errors can bypass confirmation or prevent reliable completion.
7 open issues
Handle unchanged HEAD with an existing verified Build · New Show recovery controls when preparation rechecks fail · New Prevent Git status timeouts from leaving index locks · New Resolve Git probes immediately when the timeout fires · New Make the changed-path list keyboard scrollable · New Preserve saved commit preference during recovery · New Align publishing guidance with no-change behavior · New
What changed in this PR
Improves Replica’s prototype canvas publishing when local-change checks fail or local tooling creates unnecessary prompts.
Changes:
- Streams Git status with capped path lists and full counts.
- Adds retry and committed-only recovery choices.
- Updates publishing instructions, stale-failure recovery, tests, documentation, and plugin version.
| File | Description |
|---|---|
hub/docs/prototype-canvas.md |
Documents recovery and publishing behavior. |
hub/app/javascript/utils/prototype-canvas/types.ts |
Adds unavailable checks and change lists. |
hub/app/javascript/hooks/use-canvas-publish-preference/en.ts |
Adds recovery and change-list copy. |
hub/app/javascript/hooks/use-canvas-publication/index.ts |
Handles failed checks and retries. |
hub/app/javascript/hooks/use-canvas-publication/index.test.tsx |
Tests unchecked commit rejection. |
hub/app/javascript/features/prototype-canvas-dialogs/index.tsx |
Connects recovery dialog controls. |
hub/app/javascript/components/prototype-publish-changes-dialog/styles.css |
Styles scrollable changed paths. |
hub/app/javascript/components/prototype-publish-changes-dialog/stories.tsx |
Adds recovery presentation states. |
hub/app/javascript/components/prototype-publish-changes-dialog/index.tsx |
Displays changes and recovery actions. |
hub/app/javascript/application/prototype-canvas/tests/publish-changes.test.tsx |
Covers publishing recovery interactions. |
.github/extensions/replica-prototype/working-tree-changes/index.test.mjs |
Tests streaming, classification, and failures. |
.github/extensions/replica-prototype/working-tree-changes/index.mjs |
Streams and classifies Git changes. |
.github/extensions/replica-prototype/start-canvas-server/index.test.mjs |
Tests unchecked publishing safeguards. |
.github/extensions/replica-prototype/start-canvas-server/index.mjs |
Validates recovery publishing requests. |
.github/extensions/replica-prototype/skills/replica-publish-prototype/SKILL.md |
Revises task-related commit selection. |
.github/extensions/replica-prototype/request-publish/index.test.mjs |
Updates publishing instruction assertions. |
.github/extensions/replica-prototype/README.md |
Explains recovery and tooling exclusions. |
.github/extensions/replica-prototype/read-repository-stats/index.mjs |
Uses streamed change detection. |
.github/extensions/replica-prototype/publish-target/index.mjs |
Exports checkout identity comparison. |
.github/extensions/replica-prototype/prepare-publish/index.test.mjs |
Covers failed checks and skill exclusions. |
.github/extensions/replica-prototype/prepare-publish/index.mjs |
Returns unavailable checks with verified targets. |
.github/extensions/replica-prototype/plugin.json |
Advances plugin to 1.4.0. |
.github/extensions/replica-prototype/marketplace.test.mjs |
Updates expected plugin version. |
.github/extensions/replica-prototype/get-prototype-state/index.test.mjs |
Tests failure recovery from new push evidence. |
.github/extensions/replica-prototype/get-prototype-state/index.mjs |
Clears failures superseded by push evidence. |
Review effort: Max
| ## Apply the selected mode | ||
|
|
||
| For `commit-changes`, select and commit only changes related to the current task. Preserve unrelated staged, unstaged, and untracked files. Do not blanket-stage files or include unrelated staged changes. Ask the user before committing if task-related changes cannot be separated confidently. Stop and report if there are no task-related changes or a commit fails; never publish an older commit as a fallback. | ||
| For `commit-changes`, select and commit only changes related to the current task. Preserve unrelated staged, unstaged, and untracked files, including local agent skills under `.github/skills/`, `.agents/skills/`, or `.claude/skills/` unless the task changed them. Do not blanket-stage files or include unrelated staged changes. Ask the user before committing if task-related changes cannot be separated confidently. If there are no task-related changes, make no commit and publish the verified captured `commitSha`. Stop and report if a commit fails or the target drifts; never fall back to an older commit. |
Comment on lines
+611
to
+615
| if (preparation.workingTree === "unavailable" && input.mode !== "committed-only") | ||
| throw httpError( | ||
| 409, | ||
| `Could not check local changes. Retry the check or choose Publish committed version only. ${preparation.workingTreeError}`, | ||
| ) |
Comment on lines
+11
to
+15
| const child = spawn("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], { | ||
| cwd: repositoryPath, | ||
| windowsHide: true, | ||
| stdio: ["ignore", "pipe", "pipe"], | ||
| }) |
Comment on lines
+18
to
+21
| const timer = setTimeout(() => { | ||
| timedOut = true | ||
| child.kill("SIGKILL") | ||
| }, timeoutMs) |
| {checkError ? <HubAlert title={checkError} variant="critical" layout="compact" /> : null} | ||
| {changes?.files.total ? ( | ||
| <section aria-label={copy.changedFiles}> | ||
| <ul className="publish-changes-dialog__files"> |
Comment on lines
+183
to
+186
| if (publishDialog.preparation.workingTree === "unavailable" && mode !== "committed-only") { | ||
| setPublishDialogError(publishChangesCopy.checkFailed) | ||
| return | ||
| } |
| The Publish click, or the publishing choice when a dialog is required, sends a request to Copilot chat through `session.send`. The extension does not open a separate confirmation prompt or instruct Copilot to ask again before committing or pushing. Copilot carries out the request under the host's existing tool permissions. Those settings determine whether a tool call needs approval; an additional prompt is not guaranteed. The publishing choices below control whether local edits may be committed, not a separate approval for each Git command. | ||
|
|
||
| Each Publish click checks fresh Git status, including staged, unstaged, and nonignored untracked files, rather than relying on the periodically refreshed status. With uncommitted changes and no saved commit preference, **Publish uncommitted changes?** offers **Commit changes & publish** and **Publish committed version only**. Above the checkbox it says: "Do you want to commit changes before publishing? Publishing the committed version only excludes your local uncommitted edits." Copilot selects task-related changes; there is no file-selection UI. The close icon and Escape dispatch nothing and do not save permission; there is no Cancel button. Clean checkouts continue without this dialog. | ||
| Each Publish click checks fresh Git status, including staged, unstaged, and nonignored untracked files, rather than relying on the periodically refreshed status. With uncommitted changes and no saved commit preference, **Publish uncommitted changes?** offers **Commit changes & publish** and **Publish committed version only**. Above the checkbox it says: "Do you want to commit changes before publishing? Publishing the committed version only excludes your local uncommitted edits." The dialog lists up to 20 changed paths and a count of the rest. The extension streams Git's listing and retains only those displayed paths, so large listings do not hit an output-buffer limit. Changes under `.github/skills/`, `.agents/skills/`, and `.claude/skills/` are local agent tooling: they never make the checkout count as changed, are noted as staying uncommitted, and are excluded from commits unless the task changed them. Every other path counts because the extension cannot classify it safely. Copilot selects task-related changes; there is no file-selection UI. When **Commit changes & publish** finds no task-related changes, Copilot publishes the verified current commit without creating one; a failed commit or a changed target still stops the request. The close icon and Escape dispatch nothing and do not save permission; there is no Cancel button. Clean checkouts continue without this dialog. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
Publishing could stop when a large folder overwhelmed the local-change check. Local agent skills could also trigger an unnecessary commit dialog, while an old failed request could hide a later successful push.
What changes
Git status is read as a stream, retaining only the displayed paths and full change counts. If checking fails or takes too long, the dialog shows an error banner with Retry check and Publish committed version only. It omits the description, commit button, and preference checkbox. Publishing without a successful check requires an explicit committed-only choice and still verifies the repository, branch, commit, and remote identity.
Local agent skill directories no longer trigger the uncommitted-changes dialog. Other changes remain listed for Copilot to select by task. When there are no task-related edits, the publish skill uses the verified current commit instead of stopping. New push evidence for the current checkout clears an obsolete failed request. The plugin version advances to 1.4.0.
Full devcontainer CI remains unverified: dependency setup failed with a registry DNS error, and the subsequent browser build could not find tsc. The recovery dialog was inspected in the browser using its static Storybook state; no prototype was published.