@rigour-labs/cli 7.0.0-rc.10 → 7.0.0-rc.12
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/dist/commands/hooks-push.d.ts +2 -0
- package/dist/commands/hooks-push.js +8 -1
- package/dist/commands/hooks.js +18 -3
- package/dist/commands/install-record.d.ts +2 -0
- package/dist/commands/install-record.js +5 -0
- package/dist/commands/personal.d.ts +4 -1
- package/dist/commands/personal.js +8 -1
- package/dist/commands/repo-setup.js +20 -3
- package/dist/commands/setup.js +4 -1
- package/dist/commands/shell-writes.d.ts +13 -0
- package/dist/commands/shell-writes.js +65 -0
- package/package.json +3 -3
|
@@ -27,3 +27,5 @@ export declare function pushGate(dir: string): Promise<PushGateResult>;
|
|
|
27
27
|
export declare function isPush(command: string): boolean;
|
|
28
28
|
/** The directory the push runs in: `cd <dir> && git push` or `git -C <dir> push`. */
|
|
29
29
|
export declare function pushTarget(command: string): string | undefined;
|
|
30
|
+
/** The repository a directory is in, or undefined outside one. */
|
|
31
|
+
export declare function repositoryOf(dir: string): string | undefined;
|
|
@@ -18,9 +18,15 @@ import os from 'os';
|
|
|
18
18
|
import path from 'path';
|
|
19
19
|
import { appendTaskEvent, branchBase, branchFailures, captureHumanEdits, diffFromGit, hookGoalDescription, itemLine, recordGoal, mergeBaseOf, resolveReviewer, reviewChange, reviewerCapReached, reviewerInputs, reviewerBlocks, runReviewer, runToolchain, startBackgroundReview, } from '@rigour-labs/core';
|
|
20
20
|
import { loadHookConfig } from './hooks-stop.js';
|
|
21
|
+
import { recordToolStart, toolCallId } from './shell-writes.js';
|
|
21
22
|
import { REPORT_ONLY_PREFIX, reportOnly } from './report-only.js';
|
|
22
23
|
export async function hooksPushCommand(stdin, fallbackCwd) {
|
|
23
24
|
const payload = parse(stdin);
|
|
25
|
+
// Every shell call: when it started, so the edit check after it finds the files it wrote (shell-writes.ts).
|
|
26
|
+
const started = repositoryOf(payload.cwd ?? fallbackCwd);
|
|
27
|
+
const call = toolCallId(payload);
|
|
28
|
+
if (started && call)
|
|
29
|
+
recordToolStart(started, call);
|
|
24
30
|
const command = String(payload.tool_input?.command ?? '');
|
|
25
31
|
if (!isPush(command))
|
|
26
32
|
return { exitCode: 0, message: '' };
|
|
@@ -147,7 +153,8 @@ export function pushTarget(command) {
|
|
|
147
153
|
const dir = match?.slice(1).find(Boolean);
|
|
148
154
|
return dir?.replace(/^~(?=\/|$)/, os.homedir());
|
|
149
155
|
}
|
|
150
|
-
|
|
156
|
+
/** The repository a directory is in, or undefined outside one. */
|
|
157
|
+
export function repositoryOf(dir) {
|
|
151
158
|
const result = spawnSync('git', ['rev-parse', '--show-toplevel'], { cwd: dir, encoding: 'utf8' });
|
|
152
159
|
return result.status === 0 ? result.stdout.trim() : undefined;
|
|
153
160
|
}
|
package/dist/commands/hooks.js
CHANGED
|
@@ -22,6 +22,8 @@ import { agentHome, asUserLevel, installedAgents } from './personal.js';
|
|
|
22
22
|
import { hookStdin } from './hook-input.js';
|
|
23
23
|
import { loadHookConfig } from './hooks-stop.js';
|
|
24
24
|
import { REPORT_ONLY_PREFIX, reportOnly } from './report-only.js';
|
|
25
|
+
import { filesWrittenSince, toolCallId } from './shell-writes.js';
|
|
26
|
+
import { repositoryOf } from './hooks-push.js';
|
|
25
27
|
function getHookCliVersion() {
|
|
26
28
|
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
27
29
|
const packagePath = path.resolve(thisDir, '../../package.json');
|
|
@@ -160,8 +162,9 @@ function generateClaudeHooks(checker, block, dlp = true, brief = false) {
|
|
|
160
162
|
const blockFlag = block ? ' --block' : '';
|
|
161
163
|
const checkerCommand = checkerToShellCommand(checker);
|
|
162
164
|
const hooks = {
|
|
165
|
+
// Every write is checked, whichever tool made it: a shell command's writes too (shell-writes.ts).
|
|
163
166
|
PostToolUse: [{
|
|
164
|
-
matcher: "Write|Edit|MultiEdit",
|
|
167
|
+
matcher: "Write|Edit|MultiEdit|NotebookEdit|Bash",
|
|
165
168
|
hooks: [{
|
|
166
169
|
type: "command",
|
|
167
170
|
command: `${checkerCommand} --stdin${blockFlag}`,
|
|
@@ -582,6 +585,8 @@ export function parseStdinFiles(input) {
|
|
|
582
585
|
if (typeof ti === 'object' && ti !== null) {
|
|
583
586
|
if (ti.file_path)
|
|
584
587
|
return [ti.file_path];
|
|
588
|
+
if (ti.notebook_path)
|
|
589
|
+
return [ti.notebook_path]; // Claude Code NotebookEdit
|
|
585
590
|
if (ti.path)
|
|
586
591
|
return [ti.path];
|
|
587
592
|
}
|
|
@@ -767,6 +772,7 @@ export async function hooksCheckCommand(cwd, options = {}) {
|
|
|
767
772
|
let rawStdin = '';
|
|
768
773
|
let cursorMode = false;
|
|
769
774
|
let hookSession;
|
|
775
|
+
let shellWrites;
|
|
770
776
|
if (options.stdin) {
|
|
771
777
|
rawStdin = await hookStdin();
|
|
772
778
|
// Detect Cursor/IDE hook payload format
|
|
@@ -781,15 +787,24 @@ export async function hooksCheckCommand(cwd, options = {}) {
|
|
|
781
787
|
recordSessionBaseline(cwd, session);
|
|
782
788
|
hookSession = session;
|
|
783
789
|
}
|
|
790
|
+
// A shell call: the files it wrote, found from the working tree, not the command (shell-writes.ts).
|
|
791
|
+
if (payload.tool_name === 'Bash') {
|
|
792
|
+
const repo = repositoryOf(typeof payload.cwd === 'string' ? payload.cwd : cwd);
|
|
793
|
+
const call = toolCallId(payload);
|
|
794
|
+
shellWrites = repo && call ? filesWrittenSince(repo, call) ?? [] : [];
|
|
795
|
+
}
|
|
784
796
|
}
|
|
785
797
|
catch (parseErr) {
|
|
786
798
|
// Not valid JSON — log for debugging (stderr only, stdout must stay clean)
|
|
787
799
|
process.stderr.write(`[rigour-hook-debug] stdin JSON parse failed: ${parseErr?.message?.slice(0, 100)}\n`);
|
|
788
800
|
}
|
|
789
801
|
}
|
|
790
|
-
|
|
802
|
+
// A shell call that wrote nothing: nothing to check, and nothing to say.
|
|
803
|
+
if (shellWrites && shellWrites.length === 0)
|
|
804
|
+
return;
|
|
805
|
+
const files = shellWrites ?? (options.stdin
|
|
791
806
|
? parseStdinFiles(rawStdin)
|
|
792
|
-
: (options.files ?? '').split(',').map(f => f.trim()).filter(Boolean);
|
|
807
|
+
: (options.files ?? '').split(',').map(f => f.trim()).filter(Boolean));
|
|
793
808
|
if (files.length === 0) {
|
|
794
809
|
// The old edit hook passes "$TOOL_INPUT_file_path", which the agent never sets: an empty --files. Say so on every
|
|
795
810
|
// edit, with a non-zero exit the agent shows the person, until it is migrated; it never blocks the edit.
|
|
@@ -8,6 +8,8 @@ export declare function recordCreated(cwd: string, relPath: string, content: str
|
|
|
8
8
|
export declare function unchangedSinceInstall(record: InstallRecord, relPath: string, content: string): boolean;
|
|
9
9
|
/** A server entry Rigour wrote (npx of its MCP package), which setup may re-pin; one the person changed is theirs. */
|
|
10
10
|
export declare function isRigourMcpEntry(entry: unknown): boolean;
|
|
11
|
+
/** Whether an MCP server entry, or `claude mcp get`'s description of one, runs Rigour's server: the package, or a checkout's build. */
|
|
12
|
+
export declare function namesRigourMcp(entry: unknown): boolean;
|
|
11
13
|
/** A hook script Rigour wrote (the Cline hooks): it names Rigour in its header or runs the Rigour CLI. */
|
|
12
14
|
export declare function isRigourScript(text: string): boolean;
|
|
13
15
|
/**
|
|
@@ -38,6 +38,11 @@ export function isRigourMcpEntry(entry) {
|
|
|
38
38
|
const e = entry;
|
|
39
39
|
return e?.command === 'npx' && Array.isArray(e.args) && e.args.some(a => typeof a === 'string' && a.startsWith('@rigour-labs/mcp'));
|
|
40
40
|
}
|
|
41
|
+
/** Whether an MCP server entry, or `claude mcp get`'s description of one, runs Rigour's server: the package, or a checkout's build. */
|
|
42
|
+
export function namesRigourMcp(entry) {
|
|
43
|
+
const text = typeof entry === 'string' ? entry : JSON.stringify(entry ?? '');
|
|
44
|
+
return /@rigour-labs\/mcp|rigour-mcp[\\/]+dist/.test(text);
|
|
45
|
+
}
|
|
41
46
|
/** A hook script Rigour wrote (the Cline hooks): it names Rigour in its header or runs the Rigour CLI. */
|
|
42
47
|
export function isRigourScript(text) {
|
|
43
48
|
return /hook for Rigour|@rigour-labs\/cli/.test(text) || isRigourCommand(text);
|
|
@@ -24,7 +24,10 @@ export declare function asUserLevel<T extends {
|
|
|
24
24
|
path: string;
|
|
25
25
|
content: string;
|
|
26
26
|
}>(file: T): T;
|
|
27
|
-
|
|
27
|
+
/** `taken`: a user-level server named rigour that is not Rigour's; Rigour's is not registered over it. */
|
|
28
|
+
export type McpState = 'added' | 'updated' | 'present' | 'removed' | 'absent' | 'no CLI' | 'taken';
|
|
29
|
+
/** What setup and doctor say when another server holds the name. */
|
|
30
|
+
export declare const MCP_NAME_TAKEN = "a user-level MCP server named rigour exists and is not Rigour's; rename it, then run rigour setup again";
|
|
28
31
|
/**
|
|
29
32
|
* The Rigour MCP server at user level: Claude Code through its own `claude mcp add --scope user`
|
|
30
33
|
* (its state file is Claude's, not Rigour's to edit), Cursor merged into `~/.cursor/mcp.json`.
|
|
@@ -16,7 +16,7 @@ import fs from 'fs';
|
|
|
16
16
|
import os from 'os';
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import { rigourUserDir } from '@rigour-labs/core';
|
|
19
|
-
import { isEmptyConfig, isRigourMcpEntry, readInstallRecord, recordCreated, unchangedSinceInstall, withoutRigour } from './install-record.js';
|
|
19
|
+
import { isEmptyConfig, isRigourMcpEntry, namesRigourMcp, readInstallRecord, recordCreated, unchangedSinceInstall, withoutRigour } from './install-record.js';
|
|
20
20
|
const MARKER = 'rigour-enabled';
|
|
21
21
|
/**
|
|
22
22
|
* Where the agents keep their user-level configs: RIGOUR_AGENT_HOME when set (tests, a sandbox),
|
|
@@ -136,6 +136,8 @@ export function asUserLevel(file) {
|
|
|
136
136
|
};
|
|
137
137
|
return { ...file, path: target, content: JSON.stringify(guard(JSON.parse(file.content)), null, 4) };
|
|
138
138
|
}
|
|
139
|
+
/** What setup and doctor say when another server holds the name. */
|
|
140
|
+
export const MCP_NAME_TAKEN = "a user-level MCP server named rigour exists and is not Rigour's; rename it, then run rigour setup again";
|
|
139
141
|
/**
|
|
140
142
|
* The Rigour MCP server at user level: Claude Code through its own `claude mcp add --scope user`
|
|
141
143
|
* (its state file is Claude's, not Rigour's to edit), Cursor merged into `~/.cursor/mcp.json`.
|
|
@@ -147,6 +149,9 @@ export function registerUserMcp(server) {
|
|
|
147
149
|
const get = claude(['mcp', 'get', 'rigour']);
|
|
148
150
|
if (!get.ok)
|
|
149
151
|
state = add() ? 'added' : 'no CLI';
|
|
152
|
+
// Another server holds the name: Rigour's is not registered over it, and the person is told.
|
|
153
|
+
else if (!namesRigourMcp(get.stdout))
|
|
154
|
+
state = 'taken';
|
|
150
155
|
// Rigour's own registration at another version is moved to this one, as the hooks are; one the person changed stays.
|
|
151
156
|
else if (/@rigour-labs\/mcp/.test(get.stdout) && !get.stdout.includes(server.args[server.args.length - 1])) {
|
|
152
157
|
claude(['mcp', 'remove', '--scope', 'user', 'rigour']);
|
|
@@ -169,6 +174,8 @@ export function registerUserMcp(server) {
|
|
|
169
174
|
}
|
|
170
175
|
}
|
|
171
176
|
const current = config?.mcpServers?.rigour;
|
|
177
|
+
if (current && !namesRigourMcp(current))
|
|
178
|
+
return { claude: state, cursor: 'taken' };
|
|
172
179
|
if (current && (JSON.stringify(current) === JSON.stringify(server) || !isRigourMcpEntry(current)))
|
|
173
180
|
return { claude: state, cursor: 'present' };
|
|
174
181
|
config.mcpServers = { ...(config.mcpServers ?? {}), rigour: server };
|
|
@@ -7,7 +7,8 @@ import fs from 'fs';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { getContextEvents } from '@rigour-labs/core';
|
|
9
9
|
import { resolveMCPServerConfig } from './init.js';
|
|
10
|
-
import { agentHome, enabledHere } from './personal.js';
|
|
10
|
+
import { agentHome, enabledHere, MCP_NAME_TAKEN } from './personal.js';
|
|
11
|
+
import { namesRigourMcp } from './install-record.js';
|
|
11
12
|
import { isOldEditHook } from './setup-migrations.js';
|
|
12
13
|
import { getCliVersion } from '../utils/cli-version.js';
|
|
13
14
|
import { checkoutRoots, eventsAcross } from './studio-checkouts.js';
|
|
@@ -39,7 +40,7 @@ export async function checkRepoSetup(cwd, now = new Date(), toolCalls, installed
|
|
|
39
40
|
configCheck(cwd, personal),
|
|
40
41
|
editCheck(agents, now, events, setup),
|
|
41
42
|
stopCheck(agents.map(a => a.config).join('\n'), now, events, setup),
|
|
42
|
-
mcpCheck(mcpConfig, now, calls),
|
|
43
|
+
mcpCheck(mcpConfig, now, calls, nameTaken(readFrom(agentHome()))),
|
|
43
44
|
...(version ? [version] : []),
|
|
44
45
|
prCheck(cwd),
|
|
45
46
|
];
|
|
@@ -93,8 +94,24 @@ function stopCheck(config, now, events, setup) {
|
|
|
93
94
|
return { id: 'stop', name, state: 'missing', detail: 'No stop hook configured', fix: setup };
|
|
94
95
|
return fired('stop', name, events.filter(e => e.type === 'stop_review'), now, 'finish checks');
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
/** Which agent's user-level config holds a server named rigour that is not Rigour's (personal.ts MCP_NAME_TAKEN). */
|
|
98
|
+
function nameTaken(home) {
|
|
99
|
+
for (const [agent, rel] of [['Claude Code', '.claude.json'], ['Cursor', '.cursor/mcp.json']]) {
|
|
100
|
+
try {
|
|
101
|
+
const entry = JSON.parse(home(rel) || '{}')?.mcpServers?.rigour;
|
|
102
|
+
if (entry && !namesRigourMcp(entry))
|
|
103
|
+
return agent;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// not JSON: not Rigour's to judge
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
function mcpCheck(mcpJson, now, calls, taken) {
|
|
97
112
|
const name = 'Rigour tools for agents (MCP)';
|
|
113
|
+
if (taken)
|
|
114
|
+
return { id: 'mcp', name, state: 'broken', detail: `${taken}: ${MCP_NAME_TAKEN}`, fix: 'rename the other server, then rigour setup' };
|
|
98
115
|
if (!mcpJson.includes('rigour') && calls.length === 0) {
|
|
99
116
|
return { id: 'mcp', name, state: 'missing', detail: 'Agents cannot ask Rigour for review tasks or lessons', fix: `claude mcp add --scope user rigour -- ${[resolveMCPServerConfig().command, ...resolveMCPServerConfig().args].join(' ')}` };
|
|
100
117
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -22,7 +22,7 @@ import { installGitPushHook } from './hooks-git.js';
|
|
|
22
22
|
import { hooksInitCommand, installMachineHooks, pinnedCliCommand, projectHookPaths } from './hooks.js';
|
|
23
23
|
import { initCommand, registerProjectMcp, resolveMCPServerConfig } from './init.js';
|
|
24
24
|
import { writeAgentInstructions } from './init-handshake.js';
|
|
25
|
-
import { disableHere, enableHere, registerUserMcp } from './personal.js';
|
|
25
|
+
import { disableHere, enableHere, MCP_NAME_TAKEN, registerUserMcp } from './personal.js';
|
|
26
26
|
import { applyConfigMigrations, isOldEditHook } from './setup-migrations.js';
|
|
27
27
|
import { getCliVersion } from '../utils/cli-version.js';
|
|
28
28
|
import { setupSemantic } from './semantic.js';
|
|
@@ -80,6 +80,9 @@ async function personalSetup(cwd, brief) {
|
|
|
80
80
|
console.log(chalk.yellow(`Claude Code MCP: add it with ${chalk.cyan(`claude mcp add --scope user rigour -- ${[resolveMCPServerConfig().command, ...resolveMCPServerConfig().args].join(' ')}`)}`));
|
|
81
81
|
else
|
|
82
82
|
console.log(chalk.green(`✔ Rigour tools for agents (MCP): Claude Code ${mcp.claude}, Cursor ${mcp.cursor}`));
|
|
83
|
+
for (const [agent, state] of [['Claude Code', mcp.claude], ['Cursor', mcp.cursor]])
|
|
84
|
+
if (state === 'taken')
|
|
85
|
+
console.log(chalk.yellow(`${agent}: ${MCP_NAME_TAKEN}.`));
|
|
83
86
|
}
|
|
84
87
|
async function teamSetup(cwd, options) {
|
|
85
88
|
// A personal switch here would run the machine hooks beside the committed ones.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The call's id in the hook payload: Claude Code's tool_use_id, else the session's. */
|
|
2
|
+
export declare function toolCallId(payload: {
|
|
3
|
+
tool_use_id?: unknown;
|
|
4
|
+
session_id?: unknown;
|
|
5
|
+
conversation_id?: unknown;
|
|
6
|
+
}): string | undefined;
|
|
7
|
+
/** Before the call: when it started. */
|
|
8
|
+
export declare function recordToolStart(repo: string, id: string, now?: number): void;
|
|
9
|
+
/**
|
|
10
|
+
* After the call: the files it wrote (absolute paths), changed or new in the working tree and written since it started.
|
|
11
|
+
* Undefined when no start was recorded for it (the hook before the call did not run). The record is used once.
|
|
12
|
+
*/
|
|
13
|
+
export declare function filesWrittenSince(repo: string, id: string): string[] | undefined;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files a shell command wrote, so the edit check sees writes an agent makes through its shell (a heredoc, a
|
|
3
|
+
* redirect, `sed -i`, `gofmt -w`) as it sees an Edit. Found without reading the command: the hook before the call
|
|
4
|
+
* records when it started, and the hook after it asks git which files are changed or new and were written since then.
|
|
5
|
+
*/
|
|
6
|
+
import { spawnSync } from 'child_process';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { repoStateDir } from '@rigour-labs/core';
|
|
10
|
+
/** A file's mtime and the call's start come from two clocks a few milliseconds apart: this much earlier still counts. */
|
|
11
|
+
const CLOCK_SLACK_MS = 50;
|
|
12
|
+
/** The call's id in the hook payload: Claude Code's tool_use_id, else the session's. */
|
|
13
|
+
export function toolCallId(payload) {
|
|
14
|
+
const id = payload.tool_use_id ?? payload.session_id ?? payload.conversation_id;
|
|
15
|
+
return typeof id === 'string' && /^[\w.:-]{1,200}$/.test(id) ? id : undefined;
|
|
16
|
+
}
|
|
17
|
+
function startFile(repo, id) {
|
|
18
|
+
return path.join(repoStateDir(repo), 'tool-calls', id);
|
|
19
|
+
}
|
|
20
|
+
/** Before the call: when it started. */
|
|
21
|
+
export function recordToolStart(repo, id, now = Date.now()) {
|
|
22
|
+
const file = startFile(repo, id);
|
|
23
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
24
|
+
fs.writeFileSync(file, String(now));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* After the call: the files it wrote (absolute paths), changed or new in the working tree and written since it started.
|
|
28
|
+
* Undefined when no start was recorded for it (the hook before the call did not run). The record is used once.
|
|
29
|
+
*/
|
|
30
|
+
export function filesWrittenSince(repo, id) {
|
|
31
|
+
const file = startFile(repo, id);
|
|
32
|
+
let start;
|
|
33
|
+
try {
|
|
34
|
+
start = Number(fs.readFileSync(file, 'utf8'));
|
|
35
|
+
fs.rmSync(file, { force: true });
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const status = spawnSync('git', ['status', '--porcelain=v1', '-z', '--untracked-files=all'], { cwd: repo, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 });
|
|
41
|
+
if (status.status !== 0)
|
|
42
|
+
return [];
|
|
43
|
+
const written = [];
|
|
44
|
+
const entries = status.stdout.split('\0');
|
|
45
|
+
for (let i = 0; i < entries.length; i++) {
|
|
46
|
+
const entry = entries[i];
|
|
47
|
+
if (entry.length < 4)
|
|
48
|
+
continue;
|
|
49
|
+
const code = entry.slice(0, 2);
|
|
50
|
+
if (code[0] === 'R' || code[0] === 'C')
|
|
51
|
+
i++; // a rename's old path follows; the entry holds the new one
|
|
52
|
+
if (code.includes('D'))
|
|
53
|
+
continue;
|
|
54
|
+
const full = path.join(repo, entry.slice(3));
|
|
55
|
+
try {
|
|
56
|
+
const stat = fs.statSync(full);
|
|
57
|
+
if (stat.isFile() && stat.mtimeMs >= start - CLOCK_SLACK_MS)
|
|
58
|
+
written.push(full);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// gone since git listed it
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return written;
|
|
65
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigour-labs/cli",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.12",
|
|
4
4
|
"description": "Code review that happens while your agent writes: deterministic checks on the lines it changed, quiet unless it can prove a defect, and learning from your team's fixes and dismissals. Works with Claude Code, Cursor, Codex, Cline and Windsurf.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.13"
|
|
@@ -59,12 +59,12 @@
|
|
|
59
59
|
"globby": "^14.0.1",
|
|
60
60
|
"ora": "^8.0.1",
|
|
61
61
|
"yaml": "^2.8.2",
|
|
62
|
-
"@rigour-labs/core": "7.0.0-rc.
|
|
62
|
+
"@rigour-labs/core": "7.0.0-rc.12"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@types/fs-extra": "^11.0.4",
|
|
66
66
|
"@types/node": "^25.0.3",
|
|
67
|
-
"@rigour-labs/studio": "7.0.0-rc.
|
|
67
|
+
"@rigour-labs/studio": "7.0.0-rc.12"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"build": "tsc && pnpm bundle-studio",
|