coderifts 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,6 +94,37 @@ is **never** treated as a silent NEW_ARTIFACT pass.
94
94
 
95
95
  On success the command prints a **receipt reference** when the preflight path issues one.
96
96
 
97
+ ### `coderifts registry-gate [dir]`
98
+
99
+ Local **registry admission gate** for a directory of OpenAPI/Swagger specs
100
+ (audit **3.4/9**). Runs the pure registry-validation core offline — **no cloud
101
+ calls** — so a registry CI step does not depend on CodeRifts uptime to admit
102
+ specs.
103
+
104
+ Discovers `*.yaml` / `*.yml` / `*.json` under `[dir]` (default: `.`), skips
105
+ `node_modules` and dotdirs, skips non-spec files (no `openapi`/`swagger` field),
106
+ and fails closed on unreadable files (`GATE_ERROR`) or zero specs
107
+ (`REGISTRY_EMPTY`).
108
+
109
+ | Flag | Description | Default |
110
+ |------|-------------|---------|
111
+ | `[dir]` | Registry root to scan | `.` |
112
+ | `--glob <pattern>` | Filter paths with `@coderifts/agent-guard` `matchGlob` (relative to dir) | all candidates |
113
+ | `--errors-only` | Fail only on **ERROR** severity (warnings printed, exit 0) | off |
114
+ | `--warn-only` | Advisory: print findings, always exit **0** | off |
115
+
116
+ **Severity (important):** core `endpoint_collision` is a **WARNING** and leaves
117
+ `valid: true`. This gate fails on **ERROR + WARNING** by default — it does **not**
118
+ branch on `valid` alone. Info findings are printed and do not fail.
119
+
120
+ **GitHub Actions (minimal):**
121
+
122
+ ```yaml
123
+ - uses: actions/checkout@v4
124
+ - name: Registry admission
125
+ run: npx coderifts registry-gate specs/
126
+ ```
127
+
97
128
  ### Git hook (`coderifts hook install`)
98
129
 
99
130
  Installs a **pre-push** hook that diffs the configured OpenAPI path against a
@@ -106,6 +137,67 @@ is absent). Configure with `git config coderifts.apiKey` and optional
106
137
  After upgrading the `coderifts` CLI, re-run `coderifts hook install` so the
107
138
  installed hook matches the package (already-installed hooks are not
108
139
  auto-updated).
140
+
141
+ ### Agent host files (`coderifts agent-setup`)
142
+
143
+ Writes the six CodeRifts agent-host rule files into the current repo (or `--out <dir>`):
144
+
145
+ | File | Host |
146
+ |------|------|
147
+ | `AGENTS.md` | multi-agent / open convention |
148
+ | `CLAUDE.md` | Claude Code |
149
+ | `.cursor/rules/coderifts.mdc` | Cursor |
150
+ | `.github/copilot-instructions.md` | GitHub Copilot |
151
+ | `coderifts-langgraph-policy.js` | LangGraph |
152
+ | `openai-agent-instructions.md` | OpenAI Agents SDK |
153
+
154
+ ```bash
155
+ coderifts agent-setup # write (skip existing files)
156
+ coderifts agent-setup --force # overwrite
157
+ coderifts agent-setup --check # drift vs embedded content
158
+ coderifts agent-setup --out ./docs # custom root
159
+ ```
160
+
161
+ Content is vendored from the app generator (`scripts/generate-agent-host-files.js`);
162
+ re-sync with `node scripts/sync-cli-agent-host-embed.js` when the rule source changes.
163
+
164
+ Policy template for agent/MCP APIs: `coderifts init ai-agent` (aliases: `agent`, `mcp`).
165
+
166
+ ### Required check wizard (`coderifts setup-required-check`)
167
+
168
+ Guided setup so **CodeRifts / contract-gate** is a **required status check** on
169
+ your default branch (audit **3.4/1** + **3.5**; registry admission is **3.4/9**
170
+ via `coderifts registry-gate`). The wizard:
171
+
172
+ 1. Resolves `owner/repo` from `git remote origin` (or `--repo`)
173
+ 2. Observes classic branch protection via **`gh api`** (your login — never a
174
+ CodeRifts API key)
175
+ 3. Detects **repository rulesets** that already require the check (honest
176
+ report; classic GET `/protection` does not include rulesets)
177
+ 4. **Default dry-run:** prints the exact `gh api --method PUT … --input -`
178
+ read-modify-write command that adds the check **without clobbering**
179
+ existing protection settings
180
+ 5. **`--apply`:** runs that PUT with your credentials, then **re-reads** and
181
+ only reports success if the check is required
182
+
183
+ **Why the App never writes protection:** mutating branch protection needs
184
+ `administration:write` — a trust jump we refuse. Your credentials do the write.
185
+
186
+ **Merge queues:** when this check is required, the GitHub App also handles the
187
+ `merge_group` webhook (`checks_requested`) and posts **CodeRifts / contract-gate**
188
+ on the merge group head (same gate as PR heads), so the queue does not stall.
189
+
190
+ ```bash
191
+ # Observe + print command (safe default)
192
+ coderifts setup-required-check
193
+
194
+ # Apply + re-verify
195
+ coderifts setup-required-check --apply
196
+
197
+ # One-liner for CI docs
198
+ coderifts setup-required-check --branch main
199
+ ```
200
+
109
201
  ## CI/CD Integration
110
202
 
111
203
  ### GitHub Actions
package/bin/coderifts.js CHANGED
@@ -59,6 +59,29 @@ program
59
59
  process.exit(code);
60
60
  });
61
61
 
62
+ // ── registry-gate — local OpenAPI registry admission (pure core, no cloud) ──
63
+ // Fail-closed discovery + severity selection (WARNING findings fail by default;
64
+ // never gate on core `valid` alone — endpoint_collision is warning).
65
+ // process.exit only at this boundary (library returns exitCode).
66
+ program
67
+ .command('registry-gate [dir]')
68
+ .description('Admit a directory of OpenAPI specs via local registry validation (CI gate, no cloud)')
69
+ .option('--glob <pattern>', 'Filter discovered paths with agent-guard matchGlob (relative to dir)')
70
+ .option('--errors-only', 'Fail only on ERROR severity (warnings are printed, exit 0)')
71
+ .option('--warn-only', 'Advisory: print all findings, always exit 0')
72
+ .action((dir, options) => {
73
+ const { runRegistryGate } = require('../src/commands/registry-gate');
74
+ const result = runRegistryGate({
75
+ dir: dir || '.',
76
+ glob: options.glob,
77
+ errorsOnly: !!options.errorsOnly,
78
+ warnOnly: !!options.warnOnly,
79
+ });
80
+ const code = result && typeof result.exitCode === 'number' ? result.exitCode : 1;
81
+ process.exitCode = code;
82
+ process.exit(code);
83
+ });
84
+
62
85
  // ── init command ──
63
86
  program
64
87
  .command('init [template]')
@@ -77,6 +100,107 @@ program
77
100
  await login();
78
101
  });
79
102
 
103
+ // ── setup-required-check — guided wizard for branch protection (audit 3.4/1 + 3.5) ──
104
+ // Observes classic protection + rulesets via `gh` (user credentials). Default dry-run;
105
+ // --apply does read-modify-write + re-verify. App never writes protection.
106
+ program
107
+ .command('setup-required-check')
108
+ .description('Guide setup of required status check "CodeRifts / contract-gate" (uses gh, your credentials)')
109
+ .option('--branch <name>', 'Branch to protect (default: repo default branch)')
110
+ .option('--repo <owner/repo>', 'Override owner/repo (default: git remote origin)')
111
+ .option('--apply', 'Apply the protection change (default: print the exact gh command only)')
112
+ .option('--json', 'Machine-readable JSON result')
113
+ .action(async (options) => {
114
+ const { runSetupRequiredCheck } = require('../src/commands/setup-required-check');
115
+ const result = await runSetupRequiredCheck(options);
116
+ if (result && typeof result.exitCode === 'number') {
117
+ process.exitCode = result.exitCode;
118
+ }
119
+ });
120
+
121
+ // ── status — read-only cross-layer enforcement report (ID851) ──
122
+ // GET /api/v1/enforcement-status — no GitHub writes. Distinct from `coderifts hook status`.
123
+ program
124
+ .command('status [repo]')
125
+ .description('Show cross-layer enforcement status (Runtime / Merge / Deploy) for a repo — read-only')
126
+ .option('--repo <owner/repo>', 'Repository (owner/repo); also accepted as a positional argument')
127
+ .option('--json', 'Machine-readable JSON (raw API body)')
128
+ .action(async (repoPositional, options) => {
129
+ const { runStatus } = require('../src/commands/status');
130
+ const result = await runStatus({
131
+ ...options,
132
+ repo: options.repo || repoPositional || null,
133
+ });
134
+ if (result && typeof result.exitCode === 'number') {
135
+ process.exitCode = result.exitCode;
136
+ }
137
+ });
138
+
139
+ // ── enforce — orchestrate existing setup commands (ID851 step 2) ──
140
+ // Dry-run by default; --apply threads into setup-required-check / hook.install.
141
+ // No new GitHub writes with the CodeRifts API key (user's gh for merge; local fs for hook).
142
+ program
143
+ .command('enforce [repo]')
144
+ .description('Close enforcement gaps by chaining setup-required-check / hook / deploy guidance (dry-run default; use --apply to mutate)')
145
+ .option('--repo <owner/repo>', 'Repository (owner/repo); also accepted as a positional argument')
146
+ .option('--apply', 'Actually run underlying setup commands (default: dry-run only)')
147
+ .option('--json', 'Machine-readable JSON result')
148
+ .action(async (repoPositional, options) => {
149
+ const { runEnforce } = require('../src/commands/enforce');
150
+ const result = await runEnforce({
151
+ ...options,
152
+ repo: options.repo || repoPositional || null,
153
+ apply: !!options.apply,
154
+ });
155
+ if (result && typeof result.exitCode === 'number') {
156
+ process.exitCode = result.exitCode;
157
+ }
158
+ });
159
+
160
+ // ── agent-setup — emit six agent-host rule files (vendored from app generator) ──
161
+ program
162
+ .command('agent-setup')
163
+ .description('Write AGENTS.md / CLAUDE.md / Cursor / Copilot / LangGraph / OpenAI agent rule files')
164
+ .option('--out <dir>', 'Target directory (default: current working directory)')
165
+ .option('--check', 'Exit 0 if on-disk files match embedded content; exit 1 on drift')
166
+ .option('--force', 'Overwrite existing files (default: skip collisions)')
167
+ .action((options) => {
168
+ const { runAgentSetup } = require('../src/commands/agent-setup');
169
+ runAgentSetup(options, { exit: true });
170
+ });
171
+
172
+ // ── copilot-setup — emit GitHub Copilot MCP configs (VS Code + cloud agent + custom agent) ──
173
+ // Single-source from CANONICAL_TOOL_NAMES; root keys: servers (VS Code) vs mcpServers (cloud).
174
+ program
175
+ .command('copilot-setup')
176
+ .description('Write GitHub Copilot MCP configs (.vscode/mcp.json + cloud-agent paste JSON + docs)')
177
+ .option('--out <dir>', 'Target directory (default: current working directory)')
178
+ .option('--check', 'Exit 0 if on-disk files match embedded content; exit 1 on drift')
179
+ .option('--force', 'Overwrite existing files (default: skip collisions)')
180
+ .action((options) => {
181
+ const { runCopilotSetup } = require('../src/commands/copilot-setup');
182
+ runCopilotSetup(options, { exit: true });
183
+ });
184
+
185
+ // ── lock — agent contract lockfile v1 (observed usage; ID847) ──
186
+ // GET /api/v1/lock?repo= → write coderifts.lock. Observed-only; empty agents when none recorded.
187
+ program
188
+ .command('lock [repo]')
189
+ .description('Fetch the observed agent-contract lockfile (coderifts.lock v1) for a repo')
190
+ .option('--repo <owner/repo>', 'Repository (owner/repo); also accepted as a positional argument')
191
+ .option('--out <path>', 'Output path (default: coderifts.lock in cwd)')
192
+ .option('--json', 'Print the lock document JSON to stdout (still writes --out)')
193
+ .action(async (repoPositional, options) => {
194
+ const { runLock } = require('../src/commands/lock');
195
+ const result = await runLock({
196
+ ...options,
197
+ repo: options.repo || repoPositional || null,
198
+ });
199
+ if (result && typeof result.exitCode === 'number') {
200
+ process.exitCode = result.exitCode;
201
+ }
202
+ });
203
+
80
204
  // ── hook command group ──
81
205
  const hookCmd = program
82
206
  .command('hook')