coderifts 4.1.0 → 4.2.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/CHANGELOG.md +17 -0
- package/README.md +16 -8
- package/bin/coderifts.js +9 -2
- package/dist/cli.js +229 -30
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.1.1
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **P0-2: `mapDecisionSeverity` never maps missing `execution_action` to ALLOW.**
|
|
8
|
+
Missing EA in any body shape → `INDETERMINATE` (exit 2). Legacy decision→severity
|
|
9
|
+
map is allowed only when `decision_spec_version === "1.0"` on a non-v2 body
|
|
10
|
+
(no `decision_result`, no `preflight_mode`). Top-level-only `{decision:"ALLOW"}`
|
|
11
|
+
without that pin is not permission.
|
|
12
|
+
- **P0-3: parse-gap is fail-closed by default.** Unparseable stdin and missing
|
|
13
|
+
`tool_input.file_path` → **exit 2**, stderr
|
|
14
|
+
`unparseable input — refusing (fail-closed); set CODERIFTS_ADVISORY=1 to soften`,
|
|
15
|
+
JSONL `hook_blocked` with `cause: stdin_unparseable|missing_file_path`.
|
|
16
|
+
`CODERIFTS_ADVISORY=1` restores exit 0. API-key-before-parse order is unchanged
|
|
17
|
+
(garbage stdin + no key → `missing_api_key`). Non-spec Write stays exit 0.
|
|
18
|
+
Unknown-tool-on-spec was already exit 2.
|
|
19
|
+
|
|
3
20
|
## 4.1.0
|
|
4
21
|
|
|
5
22
|
### Added
|
package/README.md
CHANGED
|
@@ -54,11 +54,12 @@ A `coderifts-report.json` file is always saved to the current directory.
|
|
|
54
54
|
|
|
55
55
|
Interactive configuration generator. Creates a `.coderifts.yml` file with industry-specific presets:
|
|
56
56
|
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
57
|
+
- `startup-lean`
|
|
58
|
+
- `growth-balanced`
|
|
59
|
+
- `fintech-strict`
|
|
60
|
+
- `public-api-safe`
|
|
61
|
+
- `microservices-internal`
|
|
62
|
+
- `ai-agent-platform`
|
|
62
63
|
|
|
63
64
|
### `coderifts login`
|
|
64
65
|
|
|
@@ -189,6 +190,13 @@ After upgrading the `coderifts` CLI, re-run `coderifts hook install` so the
|
|
|
189
190
|
installed hook matches the package (already-installed hooks are not
|
|
190
191
|
auto-updated).
|
|
191
192
|
|
|
193
|
+
2-minute Claude Code path: `coderifts hook install --claude` writes a
|
|
194
|
+
PreToolUse hook (`matcher: Write|Edit|MultiEdit` → `coderifts claude-hook`)
|
|
195
|
+
into `.claude/settings.json` (JSON-merge, backup first, idempotent).
|
|
196
|
+
`--global` writes `~/.claude/settings.json`. `--log <path>` embeds
|
|
197
|
+
`CODERIFTS_GUARD_EVENT_LOG` and `CODERIFTS_SESSION_ID` in the command.
|
|
198
|
+
Unparseable settings JSON → refuse, no write.
|
|
199
|
+
|
|
192
200
|
### Claude Code PreToolUse (`coderifts claude-hook`) — ID824
|
|
193
201
|
|
|
194
202
|
Tool-call-time gate for **Claude Code**: blocks contract-touching `Write` /
|
|
@@ -198,13 +206,13 @@ Tool-call-time gate for **Claude Code**: blocks contract-touching `Write` /
|
|
|
198
206
|
|
|
199
207
|
| Exit | Meaning |
|
|
200
208
|
|------|---------|
|
|
201
|
-
| **2** | **BLOCK** — tool call cancelled; stderr is shown to the model |
|
|
202
|
-
| **0** | Allow, or
|
|
209
|
+
| **2** | **BLOCK** — tool call cancelled; stderr is shown to the model. Default fail-closed: no key, API down, unreadable spec, parse-gap, missing `file_path` |
|
|
210
|
+
| **0** | Allow (`CONTINUE`), or skip (non-spec path / identical content). `CODERIFTS_ADVISORY=1` restores soft-allow on could-not-run sites |
|
|
203
211
|
| **1** | **Never used for deny** — Claude treats exit 1 as non-blocking (action proceeds) |
|
|
204
212
|
|
|
205
213
|
Push-time equivalent (git exit **1** on BLOCK): `coderifts hook install`.
|
|
206
214
|
|
|
207
|
-
**Install path:** `
|
|
215
|
+
**Install path:** `coderifts hook install --claude` (or `agent-setup` writes project `.claude/settings.json` when absent). Then set key + spec:
|
|
208
216
|
|
|
209
217
|
```bash
|
|
210
218
|
git config coderifts.apiKey 'cr_live_…' # or: coderifts login / CODERIFTS_API_KEY
|
package/bin/coderifts.js
CHANGED
|
@@ -283,9 +283,16 @@ const hookCmd = program
|
|
|
283
283
|
hookCmd
|
|
284
284
|
.command('install')
|
|
285
285
|
.description('Install the CodeRifts pre-push hook in the current Git repo')
|
|
286
|
-
.
|
|
286
|
+
.option('--claude', 'Write Claude Code PreToolUse hook to .claude/settings.json (JSON-merge)')
|
|
287
|
+
.option('--global', 'With --claude: write ~/.claude/settings.json instead of the project file')
|
|
288
|
+
.option('--log <path>', 'With --claude: embed CODERIFTS_GUARD_EVENT_LOG and CODERIFTS_SESSION_ID in the command')
|
|
289
|
+
.action((options) => {
|
|
287
290
|
const { install } = require('../src/commands/hook');
|
|
288
|
-
install(
|
|
291
|
+
install({
|
|
292
|
+
claude: !!options.claude,
|
|
293
|
+
global: !!options.global,
|
|
294
|
+
log: options.log,
|
|
295
|
+
});
|
|
289
296
|
});
|
|
290
297
|
|
|
291
298
|
hookCmd
|
package/dist/cli.js
CHANGED
|
@@ -3007,7 +3007,7 @@ var require_package = __commonJS({
|
|
|
3007
3007
|
"package.json"(exports2, module2) {
|
|
3008
3008
|
module2.exports = {
|
|
3009
3009
|
name: "coderifts",
|
|
3010
|
-
version: "4.
|
|
3010
|
+
version: "4.2.0",
|
|
3011
3011
|
description: "Detect breaking API changes from the command line. Works locally or with the CodeRifts cloud API.",
|
|
3012
3012
|
author: "CodeRifts <hello@coderifts.com>",
|
|
3013
3013
|
license: "MIT",
|
|
@@ -72976,6 +72976,10 @@ var require_init = __commonJS({
|
|
|
72976
72976
|
yaml: `# CodeRifts Policy: Startup Lean
|
|
72977
72977
|
# For fast-moving teams that want safety without friction.
|
|
72978
72978
|
# Catches critical breaking changes but stays out of your way.
|
|
72979
|
+
#
|
|
72980
|
+
# Decision Spec 2.0 (comment only \u2014 this file does not set agent protocol):
|
|
72981
|
+
# branch on execution_action (CONTINUE | CONTINUE_WITH_MONITORING | REQUEST_APPROVAL | STOP).
|
|
72982
|
+
# Unknown execution_action \u2192 STOP. Analyze is not permission; authorize is required to act.
|
|
72979
72983
|
|
|
72980
72984
|
failOnBreaking: true
|
|
72981
72985
|
|
|
@@ -73350,7 +73354,9 @@ generator_detection: true
|
|
|
73350
73354
|
chalk.dim(" For agent tool-call guarding: @coderifts/agent-guard requireExecutionStateMatch"),
|
|
73351
73355
|
chalk.dim(" defaults ON (absent\u2192true) \u2014 observed drift STOPS. Opt-down: 'warn' (emit, proceed)"),
|
|
73352
73356
|
chalk.dim(" or false (proceed-on-drift) \u2014 see: coderifts agent-setup"),
|
|
73353
|
-
chalk.dim(" Agent-using repo? Run: coderifts agent-setup")
|
|
73357
|
+
chalk.dim(" Agent-using repo? Run: coderifts agent-setup"),
|
|
73358
|
+
chalk.dim(" Decision Spec 2.0: branch on execution_action (CONTINUE | CONTINUE_WITH_MONITORING |"),
|
|
73359
|
+
chalk.dim(" REQUEST_APPROVAL | STOP). Unknown execution_action \u2192 STOP. Analyze is not permission.")
|
|
73354
73360
|
]);
|
|
73355
73361
|
module2.exports = {
|
|
73356
73362
|
init,
|
|
@@ -99438,6 +99444,7 @@ var require_hook = __commonJS({
|
|
|
99438
99444
|
"use strict";
|
|
99439
99445
|
var fs = require("fs");
|
|
99440
99446
|
var path = require("path");
|
|
99447
|
+
var os = require("os");
|
|
99441
99448
|
var { execSync } = require("child_process");
|
|
99442
99449
|
var HOOK_MARKER = "# CodeRifts pre-push hook";
|
|
99443
99450
|
var PRE_PUSH_SCRIPT = `#!/bin/sh
|
|
@@ -99698,12 +99705,111 @@ exit 0
|
|
|
99698
99705
|
const content = fs.readFileSync(hookPath, "utf-8");
|
|
99699
99706
|
return content.includes(HOOK_MARKER);
|
|
99700
99707
|
}
|
|
99701
|
-
|
|
99702
|
-
|
|
99708
|
+
var CLAUDE_MATCHER = "Write|Edit|MultiEdit";
|
|
99709
|
+
var CLAUDE_HOOK_BIN = "coderifts claude-hook";
|
|
99710
|
+
function claudeSettingsPath({ global: isGlobal, cwd } = {}) {
|
|
99711
|
+
if (isGlobal) return path.join(os.homedir(), ".claude", "settings.json");
|
|
99712
|
+
return path.join(cwd || process.cwd(), ".claude", "settings.json");
|
|
99713
|
+
}
|
|
99714
|
+
function claudeHookCommand(logPath) {
|
|
99715
|
+
if (!logPath) return CLAUDE_HOOK_BIN;
|
|
99716
|
+
const abs = path.resolve(String(logPath));
|
|
99717
|
+
return `CODERIFTS_GUARD_EVENT_LOG=${abs} CODERIFTS_SESSION_ID=coderifts-claude-hook ${CLAUDE_HOOK_BIN}`;
|
|
99718
|
+
}
|
|
99719
|
+
function isOurPreToolUseEntry(entry, command) {
|
|
99720
|
+
if (!entry || typeof entry !== "object") return false;
|
|
99721
|
+
if (entry.matcher !== CLAUDE_MATCHER) return false;
|
|
99722
|
+
const hooks = Array.isArray(entry.hooks) ? entry.hooks : [];
|
|
99723
|
+
return hooks.some((h) => h && h.type === "command" && String(h.command || "") === command);
|
|
99724
|
+
}
|
|
99725
|
+
function installClaudeHook(opts = {}) {
|
|
99726
|
+
const cwd = opts.cwd || process.cwd();
|
|
99727
|
+
const home = opts.homeDir || os.homedir();
|
|
99728
|
+
const dest = opts.global ? path.join(home, ".claude", "settings.json") : path.join(cwd, ".claude", "settings.json");
|
|
99729
|
+
const command = claudeHookCommand(opts.logPath);
|
|
99730
|
+
const block = {
|
|
99731
|
+
matcher: CLAUDE_MATCHER,
|
|
99732
|
+
hooks: [{ type: "command", command, timeout: 60 }]
|
|
99733
|
+
};
|
|
99734
|
+
let existing = {};
|
|
99735
|
+
let hadFile = false;
|
|
99736
|
+
if (fs.existsSync(dest)) {
|
|
99737
|
+
hadFile = true;
|
|
99738
|
+
let raw;
|
|
99739
|
+
try {
|
|
99740
|
+
raw = fs.readFileSync(dest, "utf8");
|
|
99741
|
+
} catch (err) {
|
|
99742
|
+
const message = `Error: cannot read ${dest} (${err && err.message}) \u2014 refusing to write.`;
|
|
99743
|
+
console.error(message);
|
|
99744
|
+
process.exitCode = 1;
|
|
99745
|
+
return { exitCode: 1, code: "READ_FAILED", path: dest, message };
|
|
99746
|
+
}
|
|
99747
|
+
if (String(raw).trim() !== "") {
|
|
99748
|
+
try {
|
|
99749
|
+
existing = JSON.parse(raw);
|
|
99750
|
+
} catch (err) {
|
|
99751
|
+
const message = `Error: ${dest} is not valid JSON \u2014 refusing (no write). Fix or remove the file, then re-run.`;
|
|
99752
|
+
console.error(message);
|
|
99753
|
+
process.exitCode = 1;
|
|
99754
|
+
return { exitCode: 1, code: "PARSE_FAILED", path: dest, message };
|
|
99755
|
+
}
|
|
99756
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
99757
|
+
const message = `Error: ${dest} JSON root is not an object \u2014 refusing (no write).`;
|
|
99758
|
+
console.error(message);
|
|
99759
|
+
process.exitCode = 1;
|
|
99760
|
+
return { exitCode: 1, code: "PARSE_FAILED", path: dest, message };
|
|
99761
|
+
}
|
|
99762
|
+
}
|
|
99763
|
+
}
|
|
99764
|
+
const hooksRoot = existing.hooks && typeof existing.hooks === "object" && !Array.isArray(existing.hooks) ? { ...existing.hooks } : {};
|
|
99765
|
+
const pre = Array.isArray(hooksRoot.PreToolUse) ? hooksRoot.PreToolUse.slice() : [];
|
|
99766
|
+
if (pre.some((e) => isOurPreToolUseEntry(e, command))) {
|
|
99767
|
+
console.log(`Claude Code hook already installed at ${dest} (no-op).`);
|
|
99768
|
+
return { exitCode: 0, code: "NOOP", path: dest, wrote: false };
|
|
99769
|
+
}
|
|
99770
|
+
const nextPre = pre.concat([block]);
|
|
99771
|
+
const next = {
|
|
99772
|
+
...existing,
|
|
99773
|
+
hooks: { ...hooksRoot, PreToolUse: nextPre }
|
|
99774
|
+
};
|
|
99775
|
+
const serialized = `${JSON.stringify(next, null, 2)}
|
|
99776
|
+
`;
|
|
99777
|
+
let backedUp;
|
|
99778
|
+
if (hadFile) {
|
|
99779
|
+
backedUp = `${dest}.bak`;
|
|
99780
|
+
fs.copyFileSync(dest, backedUp);
|
|
99781
|
+
}
|
|
99782
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
99783
|
+
fs.writeFileSync(dest, serialized, "utf8");
|
|
99784
|
+
console.log(`Claude Code PreToolUse hook written to ${dest}`);
|
|
99785
|
+
if (backedUp) console.log(`Backup: ${backedUp}`);
|
|
99786
|
+
console.log("matcher Write|Edit|MultiEdit \u2192 coderifts claude-hook (exit 2 = BLOCK).");
|
|
99787
|
+
return { exitCode: 0, code: "OK", path: dest, backedUp, wrote: true };
|
|
99788
|
+
}
|
|
99789
|
+
function install(options = {}) {
|
|
99790
|
+
if (options.global && !options.claude) {
|
|
99791
|
+
console.error("Error: --global requires --claude (writes ~/.claude/settings.json).");
|
|
99792
|
+
process.exitCode = 1;
|
|
99793
|
+
return { exitCode: 1, code: "USAGE" };
|
|
99794
|
+
}
|
|
99795
|
+
if (options.claude) {
|
|
99796
|
+
const r = installClaudeHook({
|
|
99797
|
+
global: !!options.global,
|
|
99798
|
+
logPath: options.log,
|
|
99799
|
+
cwd: options.cwd,
|
|
99800
|
+
homeDir: options.homeDir
|
|
99801
|
+
});
|
|
99802
|
+
if (r.exitCode !== 0) return r;
|
|
99803
|
+
}
|
|
99804
|
+
const gitDir = findGitDir(options.cwd);
|
|
99703
99805
|
if (!gitDir) {
|
|
99806
|
+
if (options.claude) {
|
|
99807
|
+
console.log("Not inside a Git repository \u2014 skipped pre-push hook.");
|
|
99808
|
+
return { exitCode: 0, code: "OK" };
|
|
99809
|
+
}
|
|
99704
99810
|
console.error("Error: Not inside a Git repository.");
|
|
99705
99811
|
process.exitCode = 1;
|
|
99706
|
-
return;
|
|
99812
|
+
return { exitCode: 1, code: "NO_GIT" };
|
|
99707
99813
|
}
|
|
99708
99814
|
const hooksDir = path.join(gitDir, "hooks");
|
|
99709
99815
|
if (!fs.existsSync(hooksDir)) {
|
|
@@ -99782,7 +99888,19 @@ exit 0
|
|
|
99782
99888
|
}
|
|
99783
99889
|
}
|
|
99784
99890
|
}
|
|
99785
|
-
module2.exports = {
|
|
99891
|
+
module2.exports = {
|
|
99892
|
+
install,
|
|
99893
|
+
uninstall,
|
|
99894
|
+
status,
|
|
99895
|
+
PRE_PUSH_SCRIPT,
|
|
99896
|
+
HOOK_MARKER,
|
|
99897
|
+
findGitDir,
|
|
99898
|
+
isCodeRiftsHook,
|
|
99899
|
+
installClaudeHook,
|
|
99900
|
+
claudeSettingsPath,
|
|
99901
|
+
claudeHookCommand,
|
|
99902
|
+
CLAUDE_MATCHER
|
|
99903
|
+
};
|
|
99786
99904
|
}
|
|
99787
99905
|
});
|
|
99788
99906
|
|
|
@@ -100063,12 +100181,12 @@ var require_agent_host_files_embedded = __commonJS({
|
|
|
100063
100181
|
".claude/settings.json"
|
|
100064
100182
|
]);
|
|
100065
100183
|
var AGENT_HOST_FILES = Object.freeze({
|
|
100066
|
-
"AGENTS.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts agent rules\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n',
|
|
100067
|
-
"CLAUDE.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n',
|
|
100068
|
-
".cursor/rules/coderifts.mdc": '---\ndescription: CodeRifts API governance \u2014 when to preflight and how to branch\nglobs:\nalwaysApply: true\n---\n\n<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n',
|
|
100069
|
-
".github/copilot-instructions.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts instructions for GitHub Copilot\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n',
|
|
100070
|
-
"coderifts-langgraph-policy.js": '// GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js\n// System policy string for a LangGraph (or similar) agent. Content is generated;\n// identical rule sentences to AGENTS.md / other formats.\n\'use strict\';\n\nmodule.exports = "Call `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\\n\\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\\n\\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\\n\\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\\n\\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not \\"proceed with caution\\" without monitoring.\\n\\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\\n\\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\\n\\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\\n\\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\\n\\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\\n\\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.";\n',
|
|
100071
|
-
"openai-agent-instructions.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts agent instructions\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n',
|
|
100184
|
+
"AGENTS.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts agent rules\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\n\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\n\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\n\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.\n',
|
|
100185
|
+
"CLAUDE.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\n\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\n\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\n\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.\n',
|
|
100186
|
+
".cursor/rules/coderifts.mdc": '---\ndescription: CodeRifts API governance \u2014 when to preflight and how to branch\nglobs:\nalwaysApply: true\n---\n\n<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\n\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\n\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\n\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.\n',
|
|
100187
|
+
".github/copilot-instructions.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts instructions for GitHub Copilot\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\n\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\n\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\n\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.\n',
|
|
100188
|
+
"coderifts-langgraph-policy.js": '// GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js\n// System policy string for a LangGraph (or similar) agent. Content is generated;\n// identical rule sentences to AGENTS.md / other formats.\n\'use strict\';\n\nmodule.exports = "Call `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\\n\\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\\n\\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\\n\\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\\n\\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not \\"proceed with caution\\" without monitoring.\\n\\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\\n\\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\\n\\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\\n\\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\\n\\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\\n\\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\\n\\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\\n\\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\\n\\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\\n\\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.";\n',
|
|
100189
|
+
"openai-agent-instructions.md": '<!-- GENERATED from CodeRifts agent-host-rule (single source). Do not edit rule sentences by hand; run: node scripts/generate-agent-host-files.js -->\n\n# CodeRifts agent instructions\n\nCall `preflight_change_set` before merge, deploy, publish, or tool registration when a contract artifact changed (OpenAPI/Swagger, GraphQL, gRPC/protobuf, AsyncAPI, MCP manifest, or agent tool schemas).\n\nSend the complete base-to-head change set: every changed contract artifact with full before and after content. Do not send a single-file subset when other contract files also change.\n\nBranch on `execution_action` only. Do not branch on `decision` and do not branch on `safe_for_agent` (not_for_control_flow_use_execution_action). Canonical `execution_action` values: CONTINUE, CONTINUE_WITH_MONITORING, REQUEST_APPROVAL, STOP.\n\nAn unrecognised `execution_action` is not permission: fail closed (halt or re-preflight). Well-known code: `not_permission_fail_closed`.\n\n`CONTINUE_WITH_MONITORING` requires a wired monitoring sink (`monitoringSinkWired`). It is not "proceed with caution" without monitoring.\n\nDo not call CodeRifts tools for a documentation-only change (README, guides, comments) with no contract artifact content change.\n\nIf you already hold a chain receipt and only need authenticity/lifecycle: `verify_receipt`. If you need a past decision by id: `get_decision_details`. Neither replaces preflight for a new change set.\n\nA receipt is operation-scoped: a merge receipt never authorizes a deploy or publish. When the operation changes, you MUST call `preflight_change_set` again with the new `context.operation` \u2014 do not decline, re-preflight.\n\nA stale or superseded receipt on a changed head requires a NEW preflight \u2014 `verify_receipt` cannot re-diff.\n\nFor mutating tools, put only the guarded version in the agent\'s tool table; keep the raw handler host-only and unreachable from that table. How you name tools is yours \u2014 this is a reachability property, not a product rename of host tools. CodeRifts cannot see or stop a raw call the host makes outside the table it returns; adopt this as a host convention, not as a guarantee from the package.\n\nCodeRifts reports a governance decision and `execution_action`; it does not by itself block merges. Blocking requires separate repository configuration (required status checks, enforcement) that this rule file does not set.\n\nTo act (mutate a contract, merge, deploy, or publish): call `preflight_change_set` with `preflight_mode` authorize. Analyze is informational (`may_execute` is always false) and is not permission. Read `execution_action` on the `decision_result` envelope.\n\nBefore acting under a held receipt: call `verify_receipt` with the intended `context` (operation, environment, repository, branch, pull_request) for THIS attempt. Do not act on a receipt whose scope does not match.\n\nAct only when `currently_authorized` is true (`control_envelope.receipt_view.currently_authorized`). A valid-looking token is not permission if `currently_authorized` is false or omitted.\n\nCommit / CAS evidence is a separate measurement (`commit_observation` on GuardOutcome). It is not a substitute for authorize + `currently_authorized`. Production hosts that want the fail-closed conjunction lock it with `profile: ENFORCING_STRICT` on withCodeRifts.\n',
|
|
100072
100190
|
".claude/settings.json": '{\n "hooks": {\n "PreToolUse": [\n {\n "matcher": "Write|Edit|MultiEdit",\n "hooks": [\n {\n "type": "command",\n "command": "coderifts claude-hook",\n "timeout": 60\n }\n ]\n }\n ]\n }\n}\n'
|
|
100073
100191
|
});
|
|
100074
100192
|
module2.exports = { AGENT_HOST_FILES, AGENT_HOST_PATHS };
|
|
@@ -101231,8 +101349,10 @@ var require_claude_hook = __commonJS({
|
|
|
101231
101349
|
" no API key / API unreachable / disk unreadable / edit-apply failure on the spec path",
|
|
101232
101350
|
" Absence of a key is not permission. Explicit opt-out: CODERIFTS_ADVISORY=1|true.",
|
|
101233
101351
|
"",
|
|
101234
|
-
"
|
|
101235
|
-
"
|
|
101352
|
+
"Parse-gap DEFAULT (exit 2): unparseable stdin / missing file_path \u2014 refusing (fail-closed);",
|
|
101353
|
+
" set CODERIFTS_ADVISORY=1 to soften. JSONL hook_blocked cause stdin_unparseable|missing_file_path.",
|
|
101354
|
+
"",
|
|
101355
|
+
"Still exit 0 (nothing to govern): non-spec path, identical content.",
|
|
101236
101356
|
"",
|
|
101237
101357
|
"CONTINUE_WITH_MONITORING: allow only if the host asserts a sink",
|
|
101238
101358
|
" (CODERIFTS_MONITORING_SINK_WIRED=1|true or git config coderifts.monitoringSinkWired).",
|
|
@@ -101431,13 +101551,22 @@ var require_claude_hook = __commonJS({
|
|
|
101431
101551
|
}
|
|
101432
101552
|
return { ok: false, reason: `unsupported tool_name for content derive: ${name}` };
|
|
101433
101553
|
}
|
|
101554
|
+
function isV2DecisionBody(d, dr) {
|
|
101555
|
+
if (dr && typeof dr === "object") return true;
|
|
101556
|
+
if (d.preflight_mode != null && d.preflight_mode !== "") return true;
|
|
101557
|
+
const ver = d.decision_spec_version;
|
|
101558
|
+
return typeof ver === "string" && ver.startsWith("2.");
|
|
101559
|
+
}
|
|
101560
|
+
function allowLegacyDecisionMap(d, dr) {
|
|
101561
|
+
return d.decision_spec_version === "1.0" && !isV2DecisionBody(d, dr);
|
|
101562
|
+
}
|
|
101434
101563
|
function mapDecisionSeverity(result) {
|
|
101435
101564
|
const d = result && typeof result === "object" && !Array.isArray(result) ? result : {};
|
|
101436
101565
|
let ea = null;
|
|
101437
101566
|
const dr = d.decision_result;
|
|
101438
|
-
if (dr && typeof dr === "object" && typeof dr.execution_action === "string") {
|
|
101567
|
+
if (dr && typeof dr === "object" && typeof dr.execution_action === "string" && dr.execution_action !== "") {
|
|
101439
101568
|
ea = dr.execution_action;
|
|
101440
|
-
} else if (typeof d.execution_action === "string") {
|
|
101569
|
+
} else if (typeof d.execution_action === "string" && d.execution_action !== "") {
|
|
101441
101570
|
ea = d.execution_action;
|
|
101442
101571
|
}
|
|
101443
101572
|
const hasDecision = d.omega_decision != null && d.omega_decision !== "" || d.decision != null && d.decision !== "" || dr && typeof dr === "object" && dr.execution_action;
|
|
@@ -101462,7 +101591,7 @@ var require_claude_hook = __commonJS({
|
|
|
101462
101591
|
} else {
|
|
101463
101592
|
severity = "REQUIRE_APPROVAL";
|
|
101464
101593
|
}
|
|
101465
|
-
} else {
|
|
101594
|
+
} else if (allowLegacyDecisionMap(d, dr)) {
|
|
101466
101595
|
const od = d.omega_decision || d.decision;
|
|
101467
101596
|
if (od == null || od === "") {
|
|
101468
101597
|
severity = "INDETERMINATE";
|
|
@@ -101470,6 +101599,8 @@ var require_claude_hook = __commonJS({
|
|
|
101470
101599
|
else if (od === "REQUIRE_APPROVAL") severity = "REQUIRE_APPROVAL";
|
|
101471
101600
|
else if (od === "WARN") severity = "WARN";
|
|
101472
101601
|
else severity = "ALLOW";
|
|
101602
|
+
} else {
|
|
101603
|
+
severity = "INDETERMINATE";
|
|
101473
101604
|
}
|
|
101474
101605
|
const decision = dr && dr.decision || d.decision || d.omega_decision || null;
|
|
101475
101606
|
const decisionId = dr && dr.decision_id || d.decision_id || null;
|
|
@@ -101480,6 +101611,45 @@ var require_claude_hook = __commonJS({
|
|
|
101480
101611
|
executionAction: ea
|
|
101481
101612
|
};
|
|
101482
101613
|
}
|
|
101614
|
+
function renderDecisionWhy(result, opts = {}) {
|
|
101615
|
+
const maxFixes = Number.isInteger(opts.maxFixes) ? opts.maxFixes : 5;
|
|
101616
|
+
const maxLines = Number.isInteger(opts.maxLines) ? opts.maxLines : 13;
|
|
101617
|
+
const d = result && typeof result === "object" && !Array.isArray(result) ? result : {};
|
|
101618
|
+
const dr = d.decision_result && typeof d.decision_result === "object" ? d.decision_result : {};
|
|
101619
|
+
const pick = (k) => dr[k] !== void 0 ? dr[k] : d[k];
|
|
101620
|
+
const arr = (v) => Array.isArray(v) ? v : [];
|
|
101621
|
+
const str = (v) => typeof v === "string" ? v.trim() : "";
|
|
101622
|
+
const lines = [];
|
|
101623
|
+
const reasonCodes = [];
|
|
101624
|
+
for (const r of arr(pick("blocking_reasons"))) {
|
|
101625
|
+
if (!r || typeof r !== "object") continue;
|
|
101626
|
+
const code = str(r.code);
|
|
101627
|
+
const message = str(r.message);
|
|
101628
|
+
if (code) reasonCodes.push(code);
|
|
101629
|
+
if (!code && !message) continue;
|
|
101630
|
+
lines.push(`- ${code || "REASON"}${message ? `: ${message}` : ""}`);
|
|
101631
|
+
}
|
|
101632
|
+
for (const r of arr(pick("degraded_reasons"))) {
|
|
101633
|
+
if (!r || typeof r !== "object") continue;
|
|
101634
|
+
const code = str(r.code);
|
|
101635
|
+
const message = str(r.message);
|
|
101636
|
+
if (!code && !message) continue;
|
|
101637
|
+
lines.push(`- degraded: ${[code, message].filter(Boolean).join(": ")}`);
|
|
101638
|
+
}
|
|
101639
|
+
const action = str(pick("required_action"));
|
|
101640
|
+
if (action) lines.push(`- action: ${action}`);
|
|
101641
|
+
const rt = pick("remediation_transaction");
|
|
101642
|
+
const changes = arr(rt && typeof rt === "object" ? rt.required_changes : null).filter((c) => c && typeof c === "object");
|
|
101643
|
+
const shown = changes.slice(0, maxFixes);
|
|
101644
|
+
for (const c of shown) {
|
|
101645
|
+
const target = str(c.target);
|
|
101646
|
+
const instruction = str(c.instruction);
|
|
101647
|
+
if (!instruction && !target) continue;
|
|
101648
|
+
lines.push(`- fix${target ? ` (${target})` : ""}: ${instruction || str(c.precise_label)}`);
|
|
101649
|
+
}
|
|
101650
|
+
if (changes.length > shown.length) lines.push(`- fix: +${changes.length - shown.length} more`);
|
|
101651
|
+
return { lines: lines.slice(0, maxLines), reasonCodes };
|
|
101652
|
+
}
|
|
101483
101653
|
async function runClaudeHook(options = {}, deps = {}) {
|
|
101484
101654
|
const errLog = deps.errLog || ((m) => console.error(String(m)));
|
|
101485
101655
|
const readStdin = deps.readStdin || (() => {
|
|
@@ -101515,7 +101685,14 @@ var require_claude_hook = __commonJS({
|
|
|
101515
101685
|
decisionId: r.decisionId != null ? r.decisionId : void 0
|
|
101516
101686
|
};
|
|
101517
101687
|
if (r.exitCode === 2) {
|
|
101518
|
-
|
|
101688
|
+
const reasons = Array.isArray(r.reasons) && r.reasons.length ? r.reasons : void 0;
|
|
101689
|
+
logEv({
|
|
101690
|
+
type: "hook_blocked",
|
|
101691
|
+
exit: 2,
|
|
101692
|
+
...extra,
|
|
101693
|
+
reasons,
|
|
101694
|
+
cause: r.reason || r.site
|
|
101695
|
+
});
|
|
101519
101696
|
} else if (r.exitCode === 0 && r.site && advisory && !strict) {
|
|
101520
101697
|
logEv({ type: "hook_advisory_passthrough", exit: 0, decision: r.decision || null, ...extra, cause: r.site });
|
|
101521
101698
|
} else {
|
|
@@ -101535,20 +101712,27 @@ var require_claude_hook = __commonJS({
|
|
|
101535
101712
|
errLog
|
|
101536
101713
|
}));
|
|
101537
101714
|
}
|
|
101715
|
+
const PARSE_GAP_STDERR = "unparseable input \u2014 refusing (fail-closed); set CODERIFTS_ADVISORY=1 to soften";
|
|
101538
101716
|
const raw = typeof options.stdin === "string" ? options.stdin : readStdin();
|
|
101539
101717
|
const parsed = parseStdinJson(raw);
|
|
101540
101718
|
if (!parsed.ok) {
|
|
101541
|
-
|
|
101542
|
-
|
|
101543
|
-
|
|
101719
|
+
if (advisory && !strict) {
|
|
101720
|
+
errLog(`CodeRifts claude-hook: ${parsed.reason} \u2014 allowing (CODERIFTS_ADVISORY)`);
|
|
101721
|
+
return emitTerminal({ exitCode: 0, reason: "stdin_unparseable", site: "stdin_unparseable" });
|
|
101722
|
+
}
|
|
101723
|
+
errLog(`CodeRifts claude-hook: ${PARSE_GAP_STDERR}`);
|
|
101724
|
+
return emitTerminal({ exitCode: 2, reason: "stdin_unparseable" });
|
|
101544
101725
|
}
|
|
101545
101726
|
const { toolName, toolInput } = parsed;
|
|
101546
101727
|
tool = toolName;
|
|
101547
101728
|
const filePath = toolInput.file_path || toolInput.filePath || toolInput.path;
|
|
101548
101729
|
if (!filePath || typeof filePath !== "string") {
|
|
101549
|
-
|
|
101550
|
-
|
|
101551
|
-
|
|
101730
|
+
if (advisory && !strict) {
|
|
101731
|
+
errLog("CodeRifts claude-hook: tool_input.file_path missing \u2014 allowing (CODERIFTS_ADVISORY)");
|
|
101732
|
+
return emitTerminal({ exitCode: 0, reason: "missing_file_path", site: "missing_file_path" });
|
|
101733
|
+
}
|
|
101734
|
+
errLog(`CodeRifts claude-hook: ${PARSE_GAP_STDERR}`);
|
|
101735
|
+
return emitTerminal({ exitCode: 2, reason: "missing_file_path" });
|
|
101552
101736
|
}
|
|
101553
101737
|
filePathKnown = filePath;
|
|
101554
101738
|
const specPath = resolveSpecPath({ ...deps, cwd });
|
|
@@ -101635,27 +101819,37 @@ var require_claude_hook = __commonJS({
|
|
|
101635
101819
|
});
|
|
101636
101820
|
}
|
|
101637
101821
|
if (mapped.severity === "BLOCK" || mapped.severity === "UNKNOWN") {
|
|
101822
|
+
const why = renderDecisionWhy(result);
|
|
101638
101823
|
errLog(
|
|
101639
|
-
|
|
101824
|
+
[
|
|
101825
|
+
`CodeRifts claude-hook: BLOCKED${decPart}${eaPart}${idPart}` + (mapped.severity === "UNKNOWN" ? " (unrecognised execution_action)" : ""),
|
|
101826
|
+
...why.lines
|
|
101827
|
+
].join("\n")
|
|
101640
101828
|
);
|
|
101641
101829
|
return emitTerminal({
|
|
101642
101830
|
exitCode: 2,
|
|
101643
101831
|
reason: mapped.severity === "UNKNOWN" ? "unknown_action" : "block",
|
|
101644
101832
|
severity: mapped.severity,
|
|
101645
101833
|
decision: mapped.decision,
|
|
101646
|
-
decisionId: mapped.decisionId
|
|
101834
|
+
decisionId: mapped.decisionId,
|
|
101835
|
+
reasons: why.reasonCodes
|
|
101647
101836
|
});
|
|
101648
101837
|
}
|
|
101649
101838
|
if (mapped.severity === "REQUIRE_APPROVAL") {
|
|
101839
|
+
const why = renderDecisionWhy(result);
|
|
101650
101840
|
errLog(
|
|
101651
|
-
|
|
101841
|
+
[
|
|
101842
|
+
`CodeRifts claude-hook: BLOCKED approval_required${decPart}${eaPart}${idPart}`,
|
|
101843
|
+
...why.lines
|
|
101844
|
+
].join("\n")
|
|
101652
101845
|
);
|
|
101653
101846
|
return emitTerminal({
|
|
101654
101847
|
exitCode: 2,
|
|
101655
101848
|
reason: "approval_required",
|
|
101656
101849
|
severity: mapped.severity,
|
|
101657
101850
|
decision: mapped.decision,
|
|
101658
|
-
decisionId: mapped.decisionId
|
|
101851
|
+
decisionId: mapped.decisionId,
|
|
101852
|
+
reasons: why.reasonCodes
|
|
101659
101853
|
});
|
|
101660
101854
|
}
|
|
101661
101855
|
if (mapped.severity === "MONITOR" || mapped.severity === "WARN") {
|
|
@@ -101694,6 +101888,7 @@ var require_claude_hook = __commonJS({
|
|
|
101694
101888
|
isSpecPath,
|
|
101695
101889
|
deriveAfterContent,
|
|
101696
101890
|
mapDecisionSeverity,
|
|
101891
|
+
renderDecisionWhy,
|
|
101697
101892
|
resolveApiKey,
|
|
101698
101893
|
resolveSpecPath,
|
|
101699
101894
|
readGitConfig,
|
|
@@ -103722,9 +103917,13 @@ ${USAGE}
|
|
|
103722
103917
|
}
|
|
103723
103918
|
});
|
|
103724
103919
|
var hookCmd = program.command("hook").description("Manage the CodeRifts pre-push Git hook");
|
|
103725
|
-
hookCmd.command("install").description("Install the CodeRifts pre-push hook in the current Git repo").action(() => {
|
|
103920
|
+
hookCmd.command("install").description("Install the CodeRifts pre-push hook in the current Git repo").option("--claude", "Write Claude Code PreToolUse hook to .claude/settings.json (JSON-merge)").option("--global", "With --claude: write ~/.claude/settings.json instead of the project file").option("--log <path>", "With --claude: embed CODERIFTS_GUARD_EVENT_LOG and CODERIFTS_SESSION_ID in the command").action((options) => {
|
|
103726
103921
|
const { install } = require_hook();
|
|
103727
|
-
install(
|
|
103922
|
+
install({
|
|
103923
|
+
claude: !!options.claude,
|
|
103924
|
+
global: !!options.global,
|
|
103925
|
+
log: options.log
|
|
103926
|
+
});
|
|
103728
103927
|
});
|
|
103729
103928
|
hookCmd.command("uninstall").description("Remove the CodeRifts pre-push hook from the current Git repo").action(() => {
|
|
103730
103929
|
const { uninstall } = require_hook();
|
package/package.json
CHANGED