Compare commits

..
Author SHA1 Message Date
dev60-review 7207d64448 docs(plugin): say where Copilot CLI's plugin comes from, and what to do about the skills catch
Copilot CLI's marketplace step installs the plugin from this repository's main branch,
not from the OpenRig package the other apps use, so its skill can be newer than the
OpenRig a person runs. And when Copilot CLI picks OpenRig's own skill router from
~/.agents/skills, it can ask for a skill pack that isn't there: the README now says to
ask it to use working-with-an-openrig-team.
2026-11-14 00:45:28 +00:00
dev60-review 90e82d5ccc docs(plugin): give Copilot CLI's verified install and seat steps
Copilot CLI 1.0.107 now has the same verified path as VS Code and Cursor: the plugin
installs from this repository's marketplace, the person's own `rig mcp serve
--front-door` server gives it a seat that holds in new sessions, and the team's
questions reach the person and their answers are recorded. The README names the
two commands for each step, and notes that Copilot CLI also loads the skills in
~/.agents/skills.
2026-11-14 00:29:50 +00:00
4 changed files with 32 additions and 45 deletions

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@ suite. Both sets are readable in the root `package.json` scripts.
| Lane | Command | Meaning |
|---|---|---|
| Portability report | `node scripts/portability-report.mjs` | lists added lines with machine-specific values; findings don't fail it by default, and `--strict` exits 1 when it finds any. The workflow (`.github/workflows/portability-report.yml`) runs it without `--strict`. |
| Portability report | `node scripts/portability-report.mjs` | lists added lines with machine-specific values; findings never fail it (`.github/workflows/portability-report.yml`) |
## The norm (web-UI freeze at 0.5.0)
@@ -70,11 +70,24 @@ codex mcp add openrig --env OPENRIG_SESSION_NAME=<address> -- rig mcp serve --fr
- **VS Code:** verified on 1.145. Older versions, such as 1.110, don't load Agent Plugins.
- **Cursor:** verified on 3.27, as a local plugin.
- **Copilot CLI:** not yet verified; the steps follow its documentation.
- **Copilot CLI:** verified on 1.0.107. Install from this repository's marketplace, and trust the folder when Copilot
CLI asks:
Install the plugin from this folder with the app's own install-from-folder step. In VS Code that's **Chat: Install Plugin
from Source**; in Cursor, copy the folder to `~/.cursor/plugins/local/openrig` and reload. The app starts one `openrig`
server, `rig mcp serve --front-door`, from the root `mcp.json`, and should load the skill.
```bash
copilot plugin marketplace add mvschwarz/openrig
copilot plugin install openrig@openrig-app
```
Unlike the other apps, this installs the plugin from this repository's main branch, not from your OpenRig package, so
its skill can be newer than the OpenRig you run.
Copilot CLI also loads the skills in `~/.agents/skills`. Where OpenRig's own skills are installed there, it can choose
OpenRig's `openrig-skills` skill before this plugin's `working-with-an-openrig-team`. If it does, it may ask for a
skill pack that isn't there and get `pack_not_found`: ask it to use `working-with-an-openrig-team`.
In VS Code and Cursor, install the plugin from this folder with the app's own install-from-folder step. In VS Code
that's **Chat: Install Plugin from Source**; in Cursor, copy the folder to `~/.cursor/plugins/local/openrig` and reload.
The app starts one `openrig` server, `rig mcp serve --front-door`, from the root `mcp.json`, and should load the skill.
- **No seat:** these apps can't set a seat for a plugin's server, so it starts with none. An app started from a shell
where `OPENRIG_SESSION_NAME` (or the older `RIGGED_SESSION_NAME`) is set passes it on, but only for that launch: on
@@ -90,14 +103,20 @@ server, `rig mcp serve --front-door`, from the root `mcp.json`, and should load
- Environment export needs an HTTP work grant, which a plugin's local server never has.
- **To give the app a seat,** add your own MCP server that runs `rig mcp serve --front-door` with
`OPENRIG_SESSION_NAME=<address>` in its environment, and turn the plugin's `openrig` server off, so the app runs one
OpenRig server. The plugin's skill stays installed. Verified on VS Code 1.145 and Cursor 3.27, where the team's
questions then reach you and your answers are recorded, across a reopen:
OpenRig server. The plugin's skill stays installed. Verified on VS Code 1.145, Cursor 3.27 and Copilot CLI 1.0.107,
where the team's questions then reach you and your answers are recorded, across a reopen:
- **VS Code:** add it to your user `mcp.json` under a name other than `openrig`, such as `openrig-seat`, and disable
the plugin's `openrig` in **MCP: List Servers**. Two servers named `openrig` are hard to tell apart, and starting
one can stop the other.
- **Cursor:** add it to `.cursor/mcp.json` (the project's or your user one), turn it on, and disable
**openrig · Plugin** in **Customize → MCPs**.
- **Copilot CLI:** add it the CLI's own way and turn the plugin's server off; not yet verified.
- **Copilot CLI:** add it, then turn the plugin's server off. Copilot CLI saves both, so the seat holds in new
sessions:
```bash
copilot mcp add openrig-seat --env OPENRIG_SESSION_NAME=<address> -- rig mcp serve --front-door
copilot mcp disable openrig
```
## What it doesn't do
+5 -8
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env node
// Lists lines added by a change that contain values tied to one machine, network or account, so
// the author can replace them with portable ones or keep them on purpose. A finding is a question, not a verdict: the default
// exits 0 with or without findings, --strict exits 1 when findings exist, and 2 is an operational error (bad argument, git failure).
// the author can replace them with portable ones or keep them on purpose. Findings never fail it: a finding is a question, not a verdict. It exits 0
// with or without findings and 2 on an operational error (bad argument, git failure).
//
// What it looks for:
// 1. Credentials: keys, tokens, passwords, key blocks.
@@ -17,7 +17,6 @@
// node scripts/portability-report.mjs --staged # what is staged for the next commit
// add --out report.md to also write the report to a file
// add --locations-only to list file and line without quoting the matched text (for public CI output)
// add --strict to exit 1 when findings exist (the default stays advisory: exit 0 either way)
import { execFileSync } from "node:child_process";
import { writeFileSync, realpathSync } from "node:fs";
@@ -134,12 +133,11 @@ export function renderReport(findings, label, { locationsOnly = false } = {}) {
}
function parseArguments(argv) {
const options = { staged: false, locationsOnly: false, strict: false };
const options = { staged: false, locationsOnly: false };
for (let index = 0; index < argv.length; index += 1) {
const key = argv[index];
if (key === "--staged") options.staged = true;
else if (key === "--locations-only") options.locationsOnly = true;
else if (key === "--strict") options.strict = true;
else if (["--from", "--to", "--out", "--repo"].includes(key)) options[key.slice(2)] = argv[++index];
else throw new Error(`Unknown argument: ${key}`);
}
@@ -165,13 +163,12 @@ export function main(argv = process.argv.slice(2)) {
label = `${from.slice(0, 8)}..${to.length > 12 ? to.slice(0, 8) : to}`;
}
const diff = git(repo, ["-c", "core.quotePath=false", "diff", "-U0", "--no-color", "--src-prefix=a/", "--dst-prefix=b/", "--diff-filter=ACMR", ...range]);
const findings = findPortabilityIssues(addedLines(diff));
const report = renderReport(findings, label, {
const report = renderReport(findPortabilityIssues(addedLines(diff)), label, {
locationsOnly: options.locationsOnly,
});
process.stdout.write(report);
if (options.out) writeFileSync(options.out, report);
return options.strict && findings.length > 0 ? 1 : 0;
return 0;
}
function invokedDirectly() {
-29
View File
@@ -173,32 +173,3 @@ test("strips Git's separator tab and leaves C-quoted filenames quoted", () => {
}
assert.deepEqual(addedLines("+++ b/ordinary name.md\t\n@@ -0,0 +1 @@\n+see /Users/alice/project\n"), [{ file: "ordinary name.md", line: 1, text: "see /Users/alice/project" }]);
});
test("--strict exits 1 on findings, keeps the advisory default at 0, and exits 0 on a clean stage", async () => {
const { mkdtempSync, writeFileSync, rmSync } = await import("node:fs");
const { tmpdir } = await import("node:os");
const { join } = await import("node:path");
const { fileURLToPath } = await import("node:url");
const { execFileSync, spawnSync } = await import("node:child_process");
const repo = mkdtempSync(join(tmpdir(), "openrig-portability-strict-"));
const script = fileURLToPath(new URL("./portability-report.mjs", import.meta.url));
try {
execFileSync("git", ["init", "--quiet", repo]);
execFileSync("git", ["-C", repo, "config", "user.email", "[email protected]"]);
execFileSync("git", ["-C", repo, "config", "user.name", "t"]);
writeFileSync(join(repo, "a.md"), "see /Users/alice/work\n");
execFileSync("git", ["-C", repo, "add", "--", "a.md"]);
const strictWithFindings = spawnSync(process.execPath, [script, "--repo", repo, "--staged", "--strict"], { encoding: "utf8" });
assert.equal(strictWithFindings.status, 1, strictWithFindings.stdout + strictWithFindings.stderr);
const advisoryWithFindings = spawnSync(process.execPath, [script, "--repo", repo, "--staged"], { encoding: "utf8" });
assert.equal(advisoryWithFindings.status, 0, advisoryWithFindings.stdout + advisoryWithFindings.stderr);
execFileSync("git", ["-C", repo, "commit", "--quiet", "-m", "seed"]);
writeFileSync(join(repo, "b.md"), "Nothing machine-specific here.\n");
execFileSync("git", ["-C", repo, "add", "--", "b.md"]);
const strictClean = spawnSync(process.execPath, [script, "--repo", repo, "--staged", "--strict"], { encoding: "utf8" });
assert.equal(strictClean.status, 0, strictClean.stdout + strictClean.stderr);
} finally { rmSync(repo, { recursive: true, force: true }); }
});