coderifts 8.5.0 → 8.6.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 8.6.1 - 2026-09-09
6
+
7
+ The generated strict workflow pins contract-gate v0.9.2 (12a2673), following the gate release.
8
+
9
+
10
+ ## 8.6.0 - 2026-09-08
11
+
12
+ - `--check` recognizes the SHA-pinned strict workflow (`coderifts/contract-gate@<40-hex>`, not only `@v0`), with states MISSING / PRESENT_UNPINNED / PRESENT_STALE / PRESENT_CURRENT; strict `--check` passes only PRESENT_CURRENT, and a generate-then-check round-trip exits 0.
13
+ - The generated strict workflow pins contract-gate v0.9.1 (df9d6a5), not the stale v0.9.0.
14
+
15
+
5
16
  ## 8.5.0 - 2026-09-07
6
17
 
7
18
  The generated check-summary reads the rulesets API when there is no classic branch protection (a ruleset-governed repo no longer reports protection_not_configured). The quickstart's Atomic example carries the issuer-grant keyring. The strict workflow template pins contract-gate at d1c348d (v0.9.0), the current gate commit.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "$comment": "GENERATED by scripts/build.js. sha256 over src/**.js + bin/**.js (path + bytes). test/build-freshness.test.js recomputes it; a mismatch means dist/cli.js is stale.",
3
- "sha256": "e9cca5e219ca1bc43448406afaae8ac9b4bd5f61dcbb880967393ea37575b354",
3
+ "sha256": "d6989104c6fcc12b512fc6dee0dd50970cd88364d9e2bec09c6c50fb019c5f14",
4
4
  "file_count": 49
5
5
  }
package/dist/cli.js CHANGED
@@ -3028,7 +3028,7 @@ var require_package = __commonJS({
3028
3028
  "package.json"(exports2, module2) {
3029
3029
  module2.exports = {
3030
3030
  name: "coderifts",
3031
- version: "8.5.0",
3031
+ version: "8.6.1",
3032
3032
  description: "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
3033
3033
  author: "CodeRifts <hello@coderifts.com>",
3034
3034
  license: "MIT",
@@ -231520,10 +231520,10 @@ var require_gate_pin = __commonJS({
231520
231520
  "src/generated/gate-pin.json"(exports2, module2) {
231521
231521
  module2.exports = {
231522
231522
  repo: "coderifts/contract-gate",
231523
- sha: "d1c348dc2047cf53de5834961563b206d7d7bbd7",
231524
- tag: "v0.9.0",
231523
+ sha: "12a2673d9bf094a1a97cb1387348018332a5c33f",
231524
+ tag: "v0.9.2",
231525
231525
  resolved_from: "https://github.com/coderifts/contract-gate refs/tags/v0",
231526
- resolved_at: "2026-09-07T07:06:00Z",
231526
+ resolved_at: "2026-09-09T18:05:11Z",
231527
231527
  note: "STRICT template pins this full commit SHA (GitHub: only a full SHA is immutable). v0 is a tag we move on every release, so it is NOT a pin. Re-run scripts/generate-gate-pin.js on each gate release; Dependabot bumps adopters."
231528
231528
  };
231529
231529
  }
@@ -231554,6 +231554,7 @@ var require_contract_gate_workflow = __commonJS({
231554
231554
  "use strict";
231555
231555
  var fs = require("fs");
231556
231556
  var path = require("path");
231557
+ var yaml = require_js_yaml();
231557
231558
  var WORKFLOW_REL = ".github/workflows/coderifts.yml";
231558
231559
  var GATE_ACTION = "coderifts/contract-gate@v0";
231559
231560
  var GATE_PIN = require_gate_pin();
@@ -231743,16 +231744,71 @@ jobs:
231743
231744
  writeFile(dest, body);
231744
231745
  return { action: "create", relPath: WORKFLOW_REL, reason: "created", exitCode: 0 };
231745
231746
  }
231746
- function workflowPresent(outDir, deps = {}) {
231747
+ var WORKFLOW_STATES = Object.freeze({
231748
+ MISSING: "MISSING",
231749
+ PRESENT_CURRENT: "PRESENT_CURRENT",
231750
+ PRESENT_STALE: "PRESENT_STALE",
231751
+ PRESENT_UNPINNED: "PRESENT_UNPINNED"
231752
+ });
231753
+ var SHA_RE = /^[0-9a-f]{40}$/i;
231754
+ var GATE_USES_RE = /^\s*-?\s*uses:\s*coderifts\/contract-gate@([0-9a-f]{40}|v[^\s#]+)/m;
231755
+ function parseGateUsesRef(uses) {
231756
+ const raw = String(uses || "").trim();
231757
+ const at = raw.lastIndexOf("@");
231758
+ if (at <= 0) return null;
231759
+ if (raw.slice(0, at) !== "coderifts/contract-gate") return null;
231760
+ return raw.slice(at + 1);
231761
+ }
231762
+ function extractContractGateRef(body) {
231763
+ try {
231764
+ const doc = yaml.load(String(body || ""));
231765
+ const jobs = doc && doc.jobs && typeof doc.jobs === "object" ? doc.jobs : {};
231766
+ for (const job of Object.values(jobs)) {
231767
+ if (!job || typeof job !== "object" || !Array.isArray(job.steps)) continue;
231768
+ for (const step of job.steps) {
231769
+ if (!step || typeof step !== "object" || step.uses == null) continue;
231770
+ const ref = parseGateUsesRef(step.uses);
231771
+ if (ref) return ref;
231772
+ }
231773
+ }
231774
+ } catch {
231775
+ }
231776
+ const m = String(body || "").match(GATE_USES_RE);
231777
+ return m ? m[1] : null;
231778
+ }
231779
+ function workflowState(outDir, deps = {}) {
231747
231780
  const exists = deps.exists || fs.existsSync.bind(fs);
231748
231781
  const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf8"));
231782
+ const expected = GATE_PIN.sha;
231783
+ const empty = { state: WORKFLOW_STATES.MISSING, ref: null, sha: null, expected };
231749
231784
  const fp = path.join(outDir, WORKFLOW_REL);
231750
- if (!exists(fp)) return false;
231785
+ if (!exists(fp)) return empty;
231786
+ let body;
231751
231787
  try {
231752
- return readFile(fp).includes(GATE_ACTION);
231788
+ body = readFile(fp);
231753
231789
  } catch {
231754
- return false;
231790
+ return empty;
231755
231791
  }
231792
+ const ref = extractContractGateRef(body);
231793
+ if (!ref) return empty;
231794
+ if (SHA_RE.test(ref)) {
231795
+ const sha = ref.toLowerCase();
231796
+ return {
231797
+ state: sha === expected ? WORKFLOW_STATES.PRESENT_CURRENT : WORKFLOW_STATES.PRESENT_STALE,
231798
+ ref,
231799
+ sha,
231800
+ expected
231801
+ };
231802
+ }
231803
+ return { state: WORKFLOW_STATES.PRESENT_UNPINNED, ref, sha: null, expected };
231804
+ }
231805
+ function workflowPresent(outDir, deps = {}) {
231806
+ return workflowState(outDir, deps).state !== WORKFLOW_STATES.MISSING;
231807
+ }
231808
+ function workflowCheckOk(state, strict) {
231809
+ if (state === WORKFLOW_STATES.MISSING) return false;
231810
+ if (strict) return state === WORKFLOW_STATES.PRESENT_CURRENT;
231811
+ return true;
231756
231812
  }
231757
231813
  module2.exports = {
231758
231814
  WORKFLOW_REL,
@@ -231766,7 +231822,11 @@ jobs:
231766
231822
  pinnedActionRef,
231767
231823
  ENFORCEMENT_DOC,
231768
231824
  writeContractGateWorkflow,
231769
- workflowPresent
231825
+ workflowPresent,
231826
+ workflowState,
231827
+ workflowCheckOk,
231828
+ extractContractGateRef,
231829
+ WORKFLOW_STATES
231770
231830
  };
231771
231831
  }
231772
231832
  });
@@ -235063,9 +235123,13 @@ var require_init_agents = __commonJS({
235063
235123
  var {
235064
235124
  WORKFLOW_REL,
235065
235125
  GATE_ACTION,
235126
+ GATE_ACTION_STRICT,
235127
+ GATE_PIN,
235066
235128
  ENFORCEMENT_DOC,
235067
235129
  writeContractGateWorkflow,
235068
- workflowPresent
235130
+ workflowState,
235131
+ workflowCheckOk,
235132
+ WORKFLOW_STATES
235069
235133
  } = require_contract_gate_workflow();
235070
235134
  var { writeAtomicV2, CONFIG_REL, WIRING_REL } = require_atomic_v2();
235071
235135
  if (process.env.NO_COLOR) chalk.level = 0;
@@ -235075,7 +235139,7 @@ var require_init_agents = __commonJS({
235075
235139
  1. repo-level MCP config (per host: .mcp.json / .cursor/mcp.json / .vscode/mcp.json)
235076
235140
  2. generated agent rule files (reuses agent-setup)
235077
235141
  3. host hook (Claude Code / VS Code Copilot via .claude/settings.json; Cursor via .cursor/hooks.json)
235078
- 4. .github/workflows/coderifts.yml (coderifts/contract-gate@v0)
235142
+ 4. .github/workflows/coderifts.yml (default @v0; --strict pins coderifts/contract-gate@<40-hex>)
235079
235143
 
235080
235144
  --hosts <list> claude, cursor, copilot, or all (default: all)
235081
235145
  --no-hook Skip host hook install
@@ -235195,6 +235259,9 @@ ${USAGE}`
235195
235259
  if (options.workflow === false) return false;
235196
235260
  return true;
235197
235261
  }
235262
+ function wantStrictWorkflow(options) {
235263
+ return !!(options.strict || options.atomicV2);
235264
+ }
235198
235265
  function padVerb(verb) {
235199
235266
  return String(verb).padEnd(7, " ");
235200
235267
  }
@@ -235239,7 +235306,8 @@ ${USAGE}`
235239
235306
  }
235240
235307
  }
235241
235308
  const workflowWanted = wantWorkflow(options);
235242
- const wfPresent = workflowWanted && workflowPresent(outDir, fsDeps);
235309
+ const wf = workflowWanted ? workflowState(outDir, fsDeps) : { state: WORKFLOW_STATES.MISSING, ref: null, sha: null, expected: GATE_PIN.sha };
235310
+ const wfOk = !workflowWanted || workflowCheckOk(wf.state, wantStrictWorkflow(options));
235243
235311
  const atomicWanted = options.atomicV2 === true;
235244
235312
  const atomicMissing = [];
235245
235313
  const atomicPresent = [];
@@ -235259,8 +235327,12 @@ ${USAGE}`
235259
235327
  },
235260
235328
  workflow: {
235261
235329
  wanted: workflowWanted,
235262
- present: wfPresent,
235263
- missing: workflowWanted && !wfPresent ? [WORKFLOW_REL] : []
235330
+ present: wfOk,
235331
+ state: workflowWanted ? wf.state : null,
235332
+ ref: wf.ref || null,
235333
+ sha: wf.sha || null,
235334
+ expected: wf.expected,
235335
+ missing: workflowWanted && !wfOk ? [WORKFLOW_REL] : []
235264
235336
  },
235265
235337
  atomicV2: {
235266
235338
  wanted: atomicWanted,
@@ -235268,7 +235340,7 @@ ${USAGE}`
235268
235340
  missing: atomicMissing
235269
235341
  }
235270
235342
  };
235271
- const missingCount = mcpMissing.length + rulesMissing.length + hooksMissing.length + (workflowWanted && !wfPresent ? 1 : 0) + atomicMissing.length;
235343
+ const missingCount = mcpMissing.length + rulesMissing.length + hooksMissing.length + (workflowWanted && !wfOk ? 1 : 0) + atomicMissing.length;
235272
235344
  return {
235273
235345
  exitCode: missingCount === 0 ? 0 : 1,
235274
235346
  pieces,
@@ -235299,7 +235371,16 @@ ${USAGE}`
235299
235371
  if (!pieces.workflow.wanted) {
235300
235372
  log(" CI workflow: skipped (--no-workflow)");
235301
235373
  } else {
235302
- log(pieces.workflow.present ? ` CI workflow: present (${WORKFLOW_REL})` : ` CI workflow: missing (${WORKFLOW_REL})`);
235374
+ const st = pieces.workflow.state || WORKFLOW_STATES.MISSING;
235375
+ let detail = WORKFLOW_REL;
235376
+ if (st === WORKFLOW_STATES.PRESENT_CURRENT && pieces.workflow.sha) {
235377
+ detail = `${WORKFLOW_REL} @ ${pieces.workflow.sha}${GATE_PIN.tag ? ` # ${GATE_PIN.tag}` : ""}`;
235378
+ } else if (st === WORKFLOW_STATES.PRESENT_STALE && pieces.workflow.sha) {
235379
+ detail = `pinned ${pieces.workflow.sha.slice(0, 12)}\u2026; current ${String(pieces.workflow.expected || "").slice(0, 12)}\u2026`;
235380
+ } else if (st === WORKFLOW_STATES.PRESENT_UNPINNED && pieces.workflow.ref) {
235381
+ detail = `coderifts/contract-gate@${pieces.workflow.ref}`;
235382
+ }
235383
+ log(` CI workflow: ${st} (${detail})`);
235303
235384
  }
235304
235385
  if (pieces.atomicV2 && pieces.atomicV2.wanted) {
235305
235386
  const st = pieces.atomicV2.missing.length === 0 ? "present" : "missing";
@@ -235426,12 +235507,13 @@ ${USAGE}`
235426
235507
  if (!wantWorkflow(options)) {
235427
235508
  items.push({ section: "workflow", action: "skip", relPath: WORKFLOW_REL, note: "--no-workflow" });
235428
235509
  } else {
235429
- const r = writeContractGateWorkflow({ outDir, dryRun, strict: !!options.strict, ...fsDeps });
235510
+ const strictWf = wantStrictWorkflow(options);
235511
+ const r = writeContractGateWorkflow({ outDir, dryRun, strict: strictWf, ...fsDeps });
235430
235512
  items.push({
235431
235513
  section: "workflow",
235432
235514
  action: r.action,
235433
235515
  relPath: r.relPath,
235434
- note: r.action === "create" ? options.strict ? `${GATE_ACTION} (STRICT require-verified-monitoring + require-grant; cr.exec.v2)` : GATE_ACTION : r.reason
235516
+ note: r.action === "create" ? strictWf ? `${GATE_ACTION_STRICT} (STRICT require-verified-monitoring + require-grant; cr.exec.v2)` : GATE_ACTION : r.reason
235435
235517
  });
235436
235518
  }
235437
235519
  if (options.atomicV2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coderifts",
3
- "version": "8.5.0",
3
+ "version": "8.6.1",
4
4
  "description": "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
5
5
  "author": "CodeRifts <hello@coderifts.com>",
6
6
  "license": "MIT",