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 +92 -0
- package/bin/coderifts.js +124 -0
- package/dist/cli.js +2142 -24
- package/package.json +1 -1
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')
|