Skip to content

feat(copilot): make cloud coding-agent files opt-in - #1517

Merged
clay-good merged 6 commits into
mainfrom
fix/copilot-cloud-opt-in
Aug 5, 2026
Merged

feat(copilot): make cloud coding-agent files opt-in#1517
clay-good merged 6 commits into
mainfrom
fix/copilot-cloud-opt-in

Conversation

@clay-good

@clay-good clay-good commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Status

Follow-up to #1274 (merged). Everything stays merged; this hardens the one piece that carried a maintenance risk, then polishes it into a first-class, discoverable feature. Ready for review.

The issue with #1274

#1274 auto-generated GitHub Copilot cloud coding-agent files (.github/workflows/copilot-setup-steps.yml + .github/agents/openspec.agent.md) whenever the github-copilot tool was selected. Two problems:

  • Invasive default. Selecting the Copilot tool wrote a GitHub Actions workflow into the user's CI — even for people who only use Copilot in their editor and never touch the cloud coding agent.
  • Maintenance coupling. Those files track GitHub's externally-owned coding-agent format (the job must be named copilot-setup-steps; the agent tools: aliases are GitHub's schema), so they drift whenever GitHub changes the contract.

What it does

Cloud files become opt-in:

Surface Behavior
openspec init (interactive) Prompts before generating (default No); persists the choice to openspec/config.yamlgithubCopilot.cloudAgent.
openspec init --copilot-cloud / --no-copilot-cloud Non-interactive opt-in / opt-out.
openspec init (non-interactive, no signal) Skips, and prints how to enable (--copilot-cloud).
openspec update Never prompts. Refreshes only when opted in (or files already exist); on explicit opt-out, removes OpenSpec-managed files.
Opt-out Removes OpenSpec-managed files; a customized file is always preserved.

Persistence uses the YAML document model, so the user's hand-authored config comments survive.

Hardening (two multi-agent review passes)

  • Correctness: fixed a reproduced crash (persistCopilotCloudOptIn threw on a scalar/sequence/null config); explicit opt-out now removes orphaned managed files instead of stranding them; --copilot-cloud warns when github-copilot isn't selected instead of silently no-opping.
  • Honest output: init reports cloud files from what is actually on disk after the write — it never claims a file a write skipped (you already own it) or that reconciliation removed; clearer prompt (names both files, distinguishes the GitHub-hosted agent from editor Copilot); a dim, decision-gated hint on update.
  • Interference: if you already have your own copilot-setup-steps.yml, init/update never touch it and now say it was preserved and that you must add the OpenSpec install step by hand.
  • Docs (was undocumented): new "GitHub Copilot cloud coding agent" section in supported-tools.md; init flags in cli.md; the config key in customization.md.

Proof it works

  • New tests: interactive prompt (accept/decline), opt-out removal + customized-file preservation, success-line accuracy over a user-owned file, config.yml variant, scalar- and sequence-root config regressions, collision reporting, flag-ignored warning, re-init honoring persisted opt-in, and config parse/warn branches.
  • Regression tests confirm customized cloud files are never overwritten or deleted (write, remove, and opt-out paths).
  • node build.js ✓, eslint src/ ✓, 2769 tests pass.

Notes / nits

  • Semver: minor (new flag + config field + changed default).
  • The only failing suites (completion.test.ts env-sensitive Zsh, command-generation/adapters.test.ts missing smol-toml dep, one config-profile case, one artifact-workflow case) fail identically on clean main — pre-existing and unrelated, verified against a clean checkout.
  • New --copilot-cloud / --no-copilot-cloud flags are registered in the shell-completion command registry to keep the parity test green.
  • A real plugin/extension system for optional tool-scoped artifacts is intentionally out of scope (future item).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added optional GitHub Copilot cloud-agent file generation during project initialization.
    • Added interactive and command-line opt-in or opt-out controls.
    • Persisted cloud-agent preferences in project configuration.
    • Updates now refresh enabled cloud files, remove managed files after opt-out, and preserve customized files.
    • Added warnings for conflicting or user-owned files.
  • Documentation

    • Documented cloud-agent setup, configuration, initialization flags, and update behavior.

Selecting the `github-copilot` tool auto-generated a GitHub Actions
workflow (.github/workflows/copilot-setup-steps.yml) plus an agent file.
Writing into a user's CI on init/update is invasive, benefits only the
narrow set of Copilot *cloud* coding-agent users, and couples us to
GitHub's externally-owned custom-agent format.

Cloud files are now opt-in:
- `openspec init` prompts before generating them (default No) and records
  the choice in openspec/config.yaml (`githubCopilot.cloudAgent`).
- `--copilot-cloud` / `--no-copilot-cloud` decide non-interactively.
- `openspec update` never prompts; it only refreshes files for projects
  that opted in, or that already have generated cloud files (so existing
  setups keep working — the migration path).

The pre-existing content-matching guarantees are unchanged and now proven
by regression tests: a user-customized cloud file is never overwritten or
deleted. Opt-in state is persisted via the YAML document model so the
user's hand-authored config comments and formatting survive untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@clay-good
clay-good requested a review from a team as a code owner August 5, 2026 17:45
@clay-good
clay-good requested review from TabishB and removed request for a team August 5, 2026 17:45
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

GitHub Copilot cloud-agent generation is now opt-in. Initialization supports CLI and interactive choices, persists explicit settings, and detects existing managed files. Updates synchronize cloud files only when enabled.

Changes

Copilot cloud-agent opt-in

Layer / File(s) Summary
Cloud-agent configuration and resolution
src/core/project-config.ts, src/core/github-copilot/cloud-agent.ts, test/core/project-config.test.ts, test/core/github-copilot-cloud-agent.test.ts
Project configuration stores githubCopilot.cloudAgent. Helpers resolve settings, preserve YAML content, detect managed files, and identify unmanaged files.
Initialization controls and persistence
src/cli/index.ts, src/core/completions/command-registry.ts, src/core/init.ts, test/core/init.test.ts
init supports opt-in and opt-out flags, prompts with No as the default, conditionally generates cloud files, persists explicit choices, and reports outcomes.
Update synchronization rules
src/core/update.ts, test/core/update.test.ts
update synchronizes cloud files only when enabled or when existing managed files indicate prior setup. Opt-out removes managed files and preserves customized files.
CLI documentation and release support
docs/cli.md, docs/customization.md, docs/supported-tools.md, .changeset/copilot-cloud-opt-in.md
Documentation and the changeset describe cloud-agent flags, configuration, update behavior, and file preservation.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant InitCommand
  participant cloud-agent
  participant ProjectConfig
  participant UpdateCommand
  CLI->>InitCommand: pass copilotCloud option
  InitCommand->>cloud-agent: resolve enablement
  cloud-agent->>ProjectConfig: read or persist cloudAgent
  InitCommand->>InitCommand: generate cloud files conditionally
  UpdateCommand->>cloud-agent: check enablement
  cloud-agent-->>UpdateCommand: return enabled state
  UpdateCommand->>UpdateCommand: synchronize cloud files conditionally
Loading

Possibly related PRs

Suggested reviewers: tabishb

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: making Copilot cloud coding-agent files opt-in.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/copilot-cloud-opt-in

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/github-copilot/cloud-agent.ts`:
- Around line 563-566: Update the persistence logic in persistCopilotCloudOptIn
to detect when the existing COPILOT_CONFIG_KEY node is scalar and replace it
with a mapping before calling doc.setIn for COPILOT_CLOUD_AGENT_KEY; preserve
existing mappings and ensure the write remains non-fatal. Add a regression test
covering githubCopilot: false followed by persistCopilotCloudOptIn(tempDir,
true).
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 35156a3b-6b85-4551-89cc-34b4bff3917b

📥 Commits

Reviewing files that changed from the base of the PR and between 13e213e and 0d600d9.

📒 Files selected for processing (10)
  • .changeset/copilot-cloud-opt-in.md
  • src/cli/index.ts
  • src/core/completions/command-registry.ts
  • src/core/github-copilot/cloud-agent.ts
  • src/core/init.ts
  • src/core/project-config.ts
  • src/core/update.ts
  • test/core/github-copilot-cloud-agent.test.ts
  • test/core/init.test.ts
  • test/core/update.test.ts

Comment thread src/core/github-copilot/cloud-agent.ts
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploying openspec-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: c4d4332
Status: ✅  Deploy successful!
Preview URL: https://cdc62903.openspec-docs.pages.dev
Branch Preview URL: https://fix-copilot-cloud-opt-in.openspec-docs.pages.dev

View logs

Follow-up hardening driven by a five-agent review swarm over the opt-in.

Correctness:
- persistCopilotCloudOptIn no longer throws on a scalar/`null` config file
  (reproduced crash); it starts a fresh map while preserving comment-only
  and empty files.
- Explicit opt-out (`--no-copilot-cloud` / `cloudAgent: false`) now removes
  OpenSpec-managed cloud files on both init and update, instead of orphaning
  them. Customized files are still never touched.
- `--copilot-cloud` / `--no-copilot-cloud` warns when github-copilot isn't
  among the selected tools, instead of silently no-opping.

UX / discoverability:
- init prints whether cloud files were written or, when skipped for want of
  a signal, how to enable them (`--copilot-cloud`).
- When the user opts in but already has their own copilot-setup-steps.yml or
  agent file, init/update say it was left untouched and that the OpenSpec
  install step must be added by hand — the direct answer to "will this affect
  my existing Copilot cloud agent?".
- Clearer interactive prompt (names both files; distinguishes the GitHub-hosted
  cloud agent from Copilot in the editor); a dim, interactive-only, decision-
  gated hint on `openspec update`; tightened flag help text.

Docs (the feature was undocumented): new "GitHub Copilot cloud coding agent"
section in supported-tools.md; init flags in cli.md; the githubCopilot.cloudAgent
key in customization.md.

Tests: interactive prompt (accept/decline), opt-out removal + customized-file
preservation, config.yml variant, scalar-config regression, collision
reporting, flag-ignored warning, re-init honoring persisted opt-in, and the
config parse/warn branches. 2763 tests pass; the only failures are pre-existing
and unrelated (completion mocks, adapters loader, one config-profile PATH case,
one experimental-alias case), verified identical on clean main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/copilot-cloud-opt-in.md:
- Line 5: Update the changeset description to state that non-interactive
openspec init without --copilot-cloud or --no-copilot-cloud skips GitHub Copilot
cloud-agent files and does not persist a configuration choice.

In `@docs/cli.md`:
- Around line 105-106: Update the --copilot-cloud and --no-copilot-cloud entries
in docs/cli.md lines 105-106 to state that they only apply when github-copilot
is selected, such as with --tools github-copilot. Add the same condition to the
corresponding behavior table entries in docs/supported-tools.md lines 128-130.

In `@docs/customization.md`:
- Around line 56-60: Update the githubCopilot.cloudAgent configuration example
in the customization documentation to clearly label false as an explicit
opt-out, and state that users should omit the optional block when they have made
no decision.

In `@docs/supported-tools.md`:
- Line 131: Update the `openspec update` documentation row to replace “the
project already has them” with wording that specifically refers to “existing
OpenSpec-managed files,” preserving the surrounding refresh and removal
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6684227a-e210-4f7f-9d84-7aa23c22be42

📥 Commits

Reviewing files that changed from the base of the PR and between 3f97128 and c4d4332.

📒 Files selected for processing (12)
  • .changeset/copilot-cloud-opt-in.md
  • docs/cli.md
  • docs/customization.md
  • docs/supported-tools.md
  • src/cli/index.ts
  • src/core/github-copilot/cloud-agent.ts
  • src/core/init.ts
  • src/core/update.ts
  • test/core/github-copilot-cloud-agent.test.ts
  • test/core/init.test.ts
  • test/core/project-config.test.ts
  • test/core/update.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/cli/index.ts
  • src/core/update.ts

"@fission-ai/openspec": minor
---

Make GitHub Copilot cloud coding-agent files opt-in. Selecting the `github-copilot` tool no longer silently writes a GitHub Actions workflow into `.github/`; `openspec init` now asks first (default No) and remembers the choice in `openspec/config.yaml` (`githubCopilot.cloudAgent`). Use `--copilot-cloud` / `--no-copilot-cloud` to decide non-interactively.

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the non-interactive default.

openspec init does not always prompt. In non-interactive mode without either flag, it skips cloud files and does not persist a choice. State this behavior here to prevent incorrect automation assumptions.

Based on PR objectives: “Non-interactive initialization without a flag skips cloud files without persisting a choice.”

🧰 Tools
🪛 LanguageTool

[uncategorized] ~5-~5: The official name of this software platform is spelled with a capital “H”.
Context: ...y writes a GitHub Actions workflow into .github/; openspec init now asks first (defa...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/copilot-cloud-opt-in.md at line 5, Update the changeset
description to state that non-interactive openspec init without --copilot-cloud
or --no-copilot-cloud skips GitHub Copilot cloud-agent files and does not
persist a configuration choice.

Comment thread docs/cli.md
Comment on lines +105 to +106
| `--copilot-cloud` | Set up GitHub Copilot [cloud coding-agent files](supported-tools.md#github-copilot-cloud-coding-agent) without prompting |
| `--no-copilot-cloud` | Skip GitHub Copilot cloud coding-agent files without prompting |

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document that the cloud flags require selecting github-copilot.

The runtime ignores --copilot-cloud and --no-copilot-cloud when github-copilot is absent from the selected tools. The documentation must state this condition.

  • docs/cli.md#L105-L106: explain that users must select github-copilot, such as with --tools github-copilot.
  • docs/supported-tools.md#L128-L130: add the same condition to the behavior table.
📍 Affects 2 files
  • docs/cli.md#L105-L106 (this comment)
  • docs/supported-tools.md#L128-L130
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/cli.md` around lines 105 - 106, Update the --copilot-cloud and
--no-copilot-cloud entries in docs/cli.md lines 105-106 to state that they only
apply when github-copilot is selected, such as with --tools github-copilot. Add
the same condition to the corresponding behavior table entries in
docs/supported-tools.md lines 128-130.

Comment thread docs/customization.md
Comment on lines +56 to +60

# Set by `openspec init` when you choose (or decline) the GitHub Copilot
# cloud coding agent; controls whether `init`/`update` generate its files.
githubCopilot:
cloudAgent: false

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify that cloudAgent: false is an explicit opt-out.

This manual configuration example persists a decision. It prevents later prompting and causes updates to remove managed cloud-agent files. Tell users to omit the optional block when no decision is intended, or label this example as an explicit opt-out.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/customization.md` around lines 56 - 60, Update the
githubCopilot.cloudAgent configuration example in the customization
documentation to clearly label false as an explicit opt-out, and state that
users should omit the optional block when they have made no decision.

Comment thread docs/supported-tools.md
| `openspec init` (interactive) | Asks whether to set up cloud files. Default is **No**. |
| `openspec init --copilot-cloud` | Sets them up without prompting (for scripts/CI). |
| `openspec init --no-copilot-cloud` | Skips them without prompting, and removes any previously generated ones. |
| `openspec update` | Never prompts. Refreshes the files only if you opted in (or the project already has them). If you opted out, it removes OpenSpec-managed cloud files. |

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Refer specifically to existing OpenSpec-managed files.

“The project already has them” can include customized or user-owned files. Replace it with “existing OpenSpec-managed files” so this sentence matches the protection guarantee in lines 132-133.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/supported-tools.md` at line 131, Update the `openspec update`
documentation row to replace “the project already has them” with wording that
specifically refers to “existing OpenSpec-managed files,” preserving the
surrounding refresh and removal behavior.

Final hardening pass (adversarial review of the opt-in polish).

- init's success line listed both cloud-file paths from the *decision* to
  write, not from what was written — so it claimed files that a write
  skipped (user already owns them) or that the alternate-agent path removed.
  It now lists only OpenSpec-managed files that actually exist after the
  write (listManagedCloudFiles), keeps the "left untouched" caveat for
  user-owned files, and reports opt-out removals in the normal output block.
- persistCopilotCloudOptIn's non-map guard used isCollection, which is also
  true for sequences, so a YAML list at the config root still made setIn
  throw. Gate on isMap so scalars AND sequences fall back to a fresh
  document; empty/comment-only files still round-trip with comments intact.
- Fixed a misleading catch comment on the opt-out removal path.

Tests: success-line accuracy over a user-owned file, sequence-root config
regression, and listManagedCloudFiles coverage. 318 tests pass across the
touched suites; build + lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot 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.

♻️ Duplicate comments (1)
src/core/github-copilot/cloud-agent.ts (1)

565-573: 🎯 Functional Correctness | 🟠 Major

Handle a non-map githubCopilot node before setIn.

This is the same unresolved issue from the previous review. The guard checks only parsed.contents. For githubCopilot: false, the root is a map, so Lines 571-573 keep parsed and doc.setIn(...) still traverses through a scalar. The YAML API throws when an intermediate setIn node is not a collection. (eemeli.org)

Because src/core/init.ts catches this persistence error, the explicit decision is silently not saved. Replace any existing non-map githubCopilot node before calling setIn. Add regression cases for scalar and sequence values.

Proposed fix
   const doc: Document =
     parsed.contents === null || isMap(parsed.contents) ? parsed : new Document();
+  if (isMap(doc.contents)) {
+    const githubCopilot = doc.get(COPILOT_CONFIG_KEY, true);
+    if (githubCopilot !== undefined && !isMap(githubCopilot)) {
+      doc.set(COPILOT_CONFIG_KEY, {});
+    }
+  }
   doc.setIn([COPILOT_CONFIG_KEY, COPILOT_CLOUD_AGENT_KEY], value);

As per coding guidelines, run the focused test with pnpm exec vitest run test/core/github-copilot-cloud-agent.test.ts -t "replaces a malformed githubCopilot scalar when persisting an explicit decision".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/github-copilot/cloud-agent.ts` around lines 565 - 573, Update the
document preparation before setIn in the cloud-agent persistence flow to replace
any existing non-map githubCopilot node, including scalar and sequence values,
with a map while preserving valid mappings. Ensure
doc.setIn([COPILOT_CONFIG_KEY, COPILOT_CLOUD_AGENT_KEY], value) no longer
traverses a malformed intermediate node, and add regression coverage for both
malformed scalar and sequence cases.

Source: Coding guidelines

🧹 Nitpick comments (1)
test/core/init.test.ts (1)

1457-1474: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Normalize the cloud-file output assertions.

COPILOT_CLOUD_FILES is defined with path.join(...), so Windows creates copilot.present with backslashes. listManagedCloudFiles() returns those same values, and the test assertions compare them directly against path.join(...) strings. Keep the filesystem paths from path.join(...) but normalize both the captured output and the expected display paths before asserting.

Proposed assertion fix
+    const displayOut = FileSystemUtils.toPosixPath(out);
+    const setupDisplay = FileSystemUtils.toPosixPath(setupRel);
+    const agentDisplay = FileSystemUtils.toPosixPath(agentRel);
-    expect(out).toContain(`GitHub Copilot cloud files: ${agentRel}`);
-    expect(out).not.toContain(`cloud files: ${setupRel}`);
-    expect(out).toContain(`Left your existing ${setupRel} untouched`);
+    expect(displayOut).toContain(`GitHub Copilot cloud files: ${agentDisplay}`);
+    expect(displayOut).not.toContain(`cloud files: ${setupDisplay}`);
+    expect(displayOut).toContain(`Left your existing ${setupDisplay} untouched`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/core/init.test.ts` around lines 1457 - 1474, Update the cloud-file
output assertions in the “opting in over a user-owned cloud file” test to
normalize path separators on both the captured console output and expected
display paths before comparing them. Keep filesystem setup and file reads using
the existing path.join values, and apply normalization only to the string
assertions involving agentRel, setupRel, and out.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/core/github-copilot/cloud-agent.ts`:
- Around line 565-573: Update the document preparation before setIn in the
cloud-agent persistence flow to replace any existing non-map githubCopilot node,
including scalar and sequence values, with a map while preserving valid
mappings. Ensure doc.setIn([COPILOT_CONFIG_KEY, COPILOT_CLOUD_AGENT_KEY], value)
no longer traverses a malformed intermediate node, and add regression coverage
for both malformed scalar and sequence cases.

---

Nitpick comments:
In `@test/core/init.test.ts`:
- Around line 1457-1474: Update the cloud-file output assertions in the “opting
in over a user-owned cloud file” test to normalize path separators on both the
captured console output and expected display paths before comparing them. Keep
filesystem setup and file reads using the existing path.join values, and apply
normalization only to the string assertions involving agentRel, setupRel, and
out.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a30e37f-afd6-4ee5-8e64-f765ddf4e484

📥 Commits

Reviewing files that changed from the base of the PR and between c4d4332 and b4113d5.

📒 Files selected for processing (4)
  • src/core/github-copilot/cloud-agent.ts
  • src/core/init.ts
  • test/core/github-copilot-cloud-agent.test.ts
  • test/core/init.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/init.ts

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Changes requested: persistCopilotCloudOptIn still throws when a valid top-level map contains a non-map githubCopilot value (false, null, or a sequence), so init swallows the error and doesn't save the explicit choice. Replace that intermediate node with a map before setIn and add a regression; I reproduced all three cases at b4113d5.

clay-good and others added 2 commits August 5, 2026 13:37
Addresses alfred review on #1517. The prior guard only fixed a non-map
config *root*; a valid top-level map whose `githubCopilot` value is itself a
scalar/null/sequence (`githubCopilot: false`, `null`, or a list) still made
`setIn(['githubCopilot','cloudAgent'], ...)` throw, which init swallowed —
so the explicit opt-in/out was never saved. Now the intermediate node is
replaced with an empty map before descending, keeping the rest of the config
and its comments intact.

Regression covers all three reproduced cases (false/null/sequence). Full
suite: 2770 pass; only the pre-existing unrelated failures remain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deeper pass on persistCopilotCloudOptIn (the function alfred flagged), driven
by an exhaustive input-shape check. Two malformed inputs still threw at
toString(): a multi-document YAML stream and a tab-indented (syntactically
invalid) file. Such a file can't be edited without corrupting it, so persist
now detects parse errors and leaves it untouched (no throw, no clobber) — it
is already invalid, so readProjectConfig ignores it regardless.

With this the function is throw-free across every shape exercised: empty,
comment-only, scalar/sequence root, a non-map githubCopilot value, anchors,
CRLF, BOM, and the two malformed cases (now skipped byte-identical).

Regression added for the multi-document case. Touched suites: 314 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The config fix now handles scalar, null, and sequence values while preserving surrounding YAML; malformed YAML stays untouched. Fresh build, lint, 314 focused tests, runtime reproductions, and the full hosted matrix pass.

@clay-good
clay-good added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 73207a6 Aug 5, 2026
17 checks passed
@clay-good
clay-good deleted the fix/copilot-cloud-opt-in branch August 5, 2026 18:58
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