Add a complete copilot_local adapter that runs GitHub Copilot CLI as a
subprocess, bringing full Copilot support to Paperclip with:
- Streaming JSONL parser for Copilot CLI v1.0.24+ event format
(message deltas, tool execution, session results)
- GHE support via --hostname / GH_HOST
- BYOK support via COPILOT_PROVIDER_BASE_URL / COPILOT_PROVIDER_API_KEY
- Ephemeral skill sync via COPILOT_SKILLS_DIRS environment variable
- Dynamic model discovery from Copilot API with fallback list
- Model detection from ~/.copilot/config.json
- Session codec for resume support (--resume=<sessionId>)
- Instructions file field with ChoosePathButton in config UI
- Login route (POST /api/companies/:companyId/agents/:id/copilot-login)
- 58 parser tests (24 server + 34 UI)
Security fixes (review feedback):
- Prevent token exfiltration via user-controlled gheHost (env-var tokens
restricted to github.com only)
- Cache key includes token fingerprint to prevent cross-tenant poisoning
- Use fetchWithRetry() instead of bare fetch() in auth.ts and models.ts
- AbortSignal.any() in fetchWithRetry to respect caller cancellation
Tested with Copilot CLI v1.0.25 on GHE (cancomictdev.ghe.com).
E2E verified: streaming, tool events, skill injection, session resume.
* ci: add Dockerfile deps stage validation to PR policy
Checks that all workspace package.json files and the patches/
directory are copied into the Dockerfile deps stage. Prevents the
Docker build from breaking when new packages or patches are added
without updating the Dockerfile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: scope Dockerfile check to deps stage and derive workspace roots
Address Greptile review feedback:
- Use awk to extract only the deps stage before grepping, preventing
false positives from COPY lines in other stages
- Derive workspace search roots from pnpm-workspace.yaml instead of
hardcoding them, so new top-level workspaces are automatically covered
* ci: guard against empty workspace roots in Dockerfile check
Fail early if pnpm-workspace.yaml parsing yields no search roots,
preventing a silent false-pass from find defaulting to cwd.
* ci: guard against empty deps stage extraction
Fail early with a clear error if awk cannot find the deps stage in the
Dockerfile, instead of producing misleading "missing COPY" errors.
* ci: deduplicate find results from overlapping workspace roots
Use sort -u instead of sort to prevent duplicate error messages when
nested workspace globs (e.g. packages/* and packages/adapters/*) cause
the same package.json to be found twice.
* ci: anchor grep to ^COPY to ignore commented-out Dockerfile lines
Prevents false negatives when a COPY directive is commented out
(e.g. # COPY packages/foo/package.json).
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Merge pr-verify.yml, pr-policy.yml, and pr-e2e.yml into a single
pr.yml with three parallel jobs (policy, verify, e2e). Benefits:
- Single concurrency group cancels all jobs on new push
- Consistent Node 24 across all jobs
- One file to maintain instead of three
The jobs still run independently (no artifact sharing) since pnpm
cache makes install fast and the upload/download overhead for
node_modules would negate the savings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align with e2e.yml and ensure CI tests exactly the committed
dependency tree. The pr-policy job already blocks lockfile changes
in PRs, so frozen-lockfile is safe here.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The playwright.config.ts had `reuseExistingServer: !!process.env.CI`
which meant CI would reuse (expect) an existing server while local
dev would start one. This is backwards — in CI Playwright should
manage the server, and in local dev you likely already have one
running.
Flip to `!process.env.CI` and remove the `CI: ""` env override
from the workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a PR E2E workflow that runs the Playwright onboarding test on
every PR targeting master. Generates a minimal config file and lets
Playwright manage the server lifecycle. Runs in skip_llm mode so
no secrets are required.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "Enable auto-merge" step runs unconditionally, even when the
lockfile didn't change and no PR exists. This causes the workflow
to fail with "lockfile PR was not found."
Use a step output to gate the auto-merge step so it only runs
when a PR was actually created or updated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scaffolds end-to-end testing with Playwright for the onboarding wizard.
Runs in skip_llm mode by default (UI-only, no LLM costs). Set
PAPERCLIP_E2E_SKIP_LLM=false for full heartbeat verification.
- tests/e2e/playwright.config.ts: Playwright config with webServer
- tests/e2e/onboarding.spec.ts: 4-step wizard flow test
- .github/workflows/e2e.yml: manual workflow_dispatch CI workflow
- package.json: test:e2e and test:e2e:headed scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplify the PR-based flow: force push to update the branch if it
already exists, and only create a new PR when one doesn't exist yet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use lockfile-bot name/email instead of github-actions[bot]
- Remove force push: close any stale PR and delete branch first,
then create a fresh branch and PR each time
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace peter-evans/create-pull-request with plain gh CLI commands to
avoid third-party supply chain risk. Uses only GitHub's own tooling
(GITHUB_TOKEN + gh CLI) to create the lockfile refresh PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The refresh-lockfile workflow was pushing directly to master, which fails
with branch protection rules. Convert to use peter-evans/create-pull-request
to create a PR instead. Exempt the bot's branch from the lockfile policy check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>