@rigour-labs/cli 7.0.0-rc.1 → 7.0.0-rc.11
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/cli.js +11 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +23 -2
- package/dist/commands/hooks-git.js +4 -2
- package/dist/commands/hooks-push.d.ts +2 -0
- package/dist/commands/hooks-push.js +14 -2
- package/dist/commands/hooks-stop.js +9 -2
- package/dist/commands/hooks.d.ts +2 -0
- package/dist/commands/hooks.js +32 -8
- package/dist/commands/learn-reviews.d.ts +2 -0
- package/dist/commands/learn-reviews.js +22 -3
- package/dist/commands/profile.js +15 -3
- package/dist/commands/repo-setup.js +12 -10
- package/dist/commands/report-only.d.ts +13 -0
- package/dist/commands/report-only.js +45 -0
- package/dist/commands/semantic.js +13 -1
- package/dist/commands/setup.d.ts +4 -0
- package/dist/commands/setup.js +100 -14
- package/dist/commands/shell-writes.d.ts +13 -0
- package/dist/commands/shell-writes.js +65 -0
- package/dist/commands/studio-learning.d.ts +2 -0
- package/dist/commands/studio-learning.js +5 -3
- package/dist/commands/team.js +8 -2
- package/dist/commands/uninstall.js +2 -1
- package/package.json +3 -3
- package/studio-dist/assets/{index-D5EEZJUE.js → index-CmWtilgA.js} +17 -17
- package/studio-dist/index.html +1 -1
package/dist/commands/setup.js
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* at user level, guarded so they run only where Rigour is switched on; this repository is switched
|
|
6
6
|
* on inside its git directory (personal.ts). For trying Rigour, or using it alone.
|
|
7
7
|
*
|
|
8
|
-
* Team (`--team
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Team (`--team`): rigour.yml, the project's agent hooks and its MCP server are written into the
|
|
9
|
+
* repository, so everyone who clones gets the same gate. Agent instruction files only with
|
|
10
|
+
* `--instructions`. Only `--team` ever writes into the working tree: in a repository that commits its
|
|
11
|
+
* own Rigour hooks, a plain `rigour setup` leaves every file as committed (the team's install runs).
|
|
11
12
|
*
|
|
12
13
|
* Both install semantic search once per machine (semantic.ts) unless --no-semantic, end with the
|
|
13
14
|
* same checks as `rigour doctor`, and are taken back out by `rigour uninstall`.
|
|
@@ -18,22 +19,40 @@ import fs from 'fs';
|
|
|
18
19
|
import path from 'path';
|
|
19
20
|
import { printRepoSetup } from './doctor.js';
|
|
20
21
|
import { installGitPushHook } from './hooks-git.js';
|
|
21
|
-
import { hooksInitCommand, installMachineHooks, pinnedCliCommand } from './hooks.js';
|
|
22
|
+
import { hooksInitCommand, installMachineHooks, pinnedCliCommand, projectHookPaths } from './hooks.js';
|
|
22
23
|
import { initCommand, registerProjectMcp, resolveMCPServerConfig } from './init.js';
|
|
23
24
|
import { writeAgentInstructions } from './init-handshake.js';
|
|
24
25
|
import { disableHere, enableHere, registerUserMcp } from './personal.js';
|
|
25
|
-
import { applyConfigMigrations } from './setup-migrations.js';
|
|
26
|
+
import { applyConfigMigrations, isOldEditHook } from './setup-migrations.js';
|
|
27
|
+
import { getCliVersion } from '../utils/cli-version.js';
|
|
26
28
|
import { setupSemantic } from './semantic.js';
|
|
29
|
+
import { setReportOnlyHere, TEAM_REQUIRES_BLOCKING } from './report-only.js';
|
|
30
|
+
import yaml from 'yaml';
|
|
27
31
|
const AGENT_NAME = { claude: 'Claude Code', cursor: 'Cursor', cline: 'Cline', windsurf: 'Windsurf' };
|
|
28
32
|
export async function setupCommand(cwd = process.cwd(), options = {}) {
|
|
29
|
-
const team = options.team
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
const team = !!options.team;
|
|
34
|
+
const committed = team ? [] : committedRigourHooks(cwd);
|
|
35
|
+
const mode = team ? 'team: committed to this repository' : committed.length ? "the team's install: nothing in your working tree" : 'personal: nothing in your working tree';
|
|
36
|
+
console.log(chalk.bold.cyan(`\nRigour setup (${mode})\n`));
|
|
37
|
+
if (team) {
|
|
38
|
+
const touched = trackedFiles(cwd, ['rigour.yml', ...rigourInstallPaths()]);
|
|
39
|
+
if (touched.length)
|
|
40
|
+
console.log(chalk.yellow(`Writes into these committed files (commit the result so everyone gets it): ${touched.join(', ')}\n`));
|
|
32
41
|
await teamSetup(cwd, options);
|
|
33
|
-
|
|
42
|
+
}
|
|
43
|
+
else if (committed.length)
|
|
44
|
+
await leaveTeamInstall(cwd, committed, !!options.instructions);
|
|
45
|
+
else {
|
|
46
|
+
if (trackedFiles(cwd, ['rigour.yml']).length)
|
|
47
|
+
console.log(chalk.dim('This repository commits rigour.yml; `rigour setup --team` commits hooks for everyone. This setup is yours alone.\n'));
|
|
34
48
|
await personalSetup(cwd, options.brief !== false);
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
}
|
|
50
|
+
// rigour.yml is the team's file: only --team changes it (doctor's checks below name what is due).
|
|
51
|
+
if (team)
|
|
52
|
+
for (const change of applyConfigMigrations(cwd))
|
|
53
|
+
console.log(chalk.green(`✔ Migrated ${change}`));
|
|
54
|
+
if (options.reportOnly || options.block)
|
|
55
|
+
setGateMode(cwd, team, !!options.reportOnly);
|
|
37
56
|
if (options.semantic !== false)
|
|
38
57
|
await setupSemantic(cwd);
|
|
39
58
|
await printRepoSetup(cwd);
|
|
@@ -75,7 +94,74 @@ async function teamSetup(cwd, options) {
|
|
|
75
94
|
else
|
|
76
95
|
await initCommand(cwd, { instructions: options.instructions, brief: options.brief !== false });
|
|
77
96
|
}
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Report-only or blocking, for this repository: the person's switch in the git directory, and with --team the team's
|
|
99
|
+
* in rigour.yml (`hooks.report_only`: true, or false with --block), so everyone who clones starts the same way.
|
|
100
|
+
*/
|
|
101
|
+
function setGateMode(cwd, team, report) {
|
|
102
|
+
setReportOnlyHere(cwd, report);
|
|
103
|
+
const file = path.join(cwd, 'rigour.yml');
|
|
104
|
+
if (!team && report && fs.existsSync(file) && yaml.parse(fs.readFileSync(file, 'utf8'))?.hooks?.report_only === false) {
|
|
105
|
+
console.log(chalk.yellow(TEAM_REQUIRES_BLOCKING));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (team && fs.existsSync(file)) {
|
|
109
|
+
const doc = yaml.parseDocument(fs.readFileSync(file, 'utf8'));
|
|
110
|
+
// A team that turns blocking on means block: an explicit false, the floor no person's switch lowers.
|
|
111
|
+
doc.setIn(['hooks', 'report_only'], report);
|
|
112
|
+
fs.writeFileSync(file, doc.toString());
|
|
113
|
+
}
|
|
114
|
+
console.log(report
|
|
115
|
+
? chalk.green(`✔ Report only: the edit check, the stop review and the push gate say what they would block and block nothing${team ? ' (hooks.report_only in rigour.yml)' : ''}. A real credential is still refused. Make them block: rigour setup${team ? ' --team' : ''} --block`)
|
|
116
|
+
: chalk.green('✔ The edit check, the stop review and the push gate block again.'));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The team's install, as committed here: tracked project hook and MCP files that run Rigour. Their agents already run
|
|
120
|
+
* them, so a person's setup changes none of them, and personal hooks beside them would run every check twice.
|
|
121
|
+
*/
|
|
122
|
+
async function leaveTeamInstall(cwd, committed, instructions) {
|
|
123
|
+
disableHere(cwd, false);
|
|
124
|
+
const text = committed.map(file => fs.readFileSync(path.join(cwd, file), 'utf8')).join('\n');
|
|
125
|
+
const pins = [...new Set([...text.matchAll(/@rigour-labs\/cli@([0-9A-Za-z.-]+)/g)].map(m => m[1]))];
|
|
126
|
+
const installed = getCliVersion();
|
|
127
|
+
const stale = pins.filter(pin => pin !== installed);
|
|
128
|
+
console.log(chalk.green('✔ This repository commits its own Rigour install, and your agents run it. Left as committed:'));
|
|
129
|
+
for (const file of committed)
|
|
130
|
+
console.log(chalk.dim(` ${file}`));
|
|
131
|
+
if (stale.length) {
|
|
132
|
+
// The committed pin is what the agents run: name it, and what it costs, since this setup does not move it.
|
|
133
|
+
const caveat = isOldEditHook(text) ? ' (its edit hook checks nothing)' : '';
|
|
134
|
+
console.log(chalk.yellow(` These hooks pin Rigour ${pins.join(', ')}; they keep running that version${caveat} until someone runs \`rigour setup --team\` and commits the result. Installed here: ${installed}.`));
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
console.log(chalk.dim(' To change it for everyone: rigour setup --team, then commit the result.'));
|
|
138
|
+
// This clone's own: git's pre-push hook lives in the git directory, never in the working tree.
|
|
139
|
+
const push = installGitPushHook(cwd, pinnedCliCommand(), { workingTree: false });
|
|
140
|
+
if (push.action === 'managed elsewhere')
|
|
141
|
+
console.log(chalk.yellow(`Git pre-push hooks are managed outside this repository (${push.path}); add: ${pinnedCliCommand()} hooks push --git "$@" || exit $?`));
|
|
142
|
+
else if (push.action !== 'no repository')
|
|
143
|
+
console.log(chalk.green(`✔ Push gate: git's pre-push hook (${push.action}); the only thing installed here`));
|
|
144
|
+
// Asked for by name: written only where the repository has none, so no committed file changes.
|
|
145
|
+
if (instructions)
|
|
146
|
+
await writeAgentInstructions(cwd);
|
|
147
|
+
}
|
|
148
|
+
/** Where a team's Rigour install lives in the repository: the project hook and MCP configs. */
|
|
149
|
+
function rigourInstallPaths() {
|
|
150
|
+
return [...projectHookPaths(), '.mcp.json', '.cursor/mcp.json'];
|
|
151
|
+
}
|
|
152
|
+
/** Which of these paths git tracks here. */
|
|
153
|
+
function trackedFiles(cwd, paths) {
|
|
154
|
+
const tracked = spawnSync('git', ['ls-files', '--', ...paths], { cwd, encoding: 'utf8' });
|
|
155
|
+
return tracked.status === 0 ? tracked.stdout.split('\n').filter(Boolean) : [];
|
|
156
|
+
}
|
|
157
|
+
/** The tracked files of a team's Rigour install: project hook and MCP configs that name Rigour. */
|
|
158
|
+
function committedRigourHooks(cwd) {
|
|
159
|
+
return trackedFiles(cwd, rigourInstallPaths()).filter(file => {
|
|
160
|
+
try {
|
|
161
|
+
return /rigour/i.test(fs.readFileSync(path.join(cwd, file), 'utf8'));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
81
167
|
}
|
|
@@ -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
|
+
}
|
|
@@ -50,6 +50,8 @@ export interface LessonJourney {
|
|
|
50
50
|
};
|
|
51
51
|
/** A candidate only review bots raised, nothing waiting on a person (core quietBotCandidate): hidden until a person asks to see bot points. */
|
|
52
52
|
fromBots?: true;
|
|
53
|
+
/** A person's last decision on a review lesson (promoted, rejected, not a rule) can be taken back to a candidate (core takeBackable). */
|
|
54
|
+
canTakeBack?: true;
|
|
53
55
|
/**
|
|
54
56
|
* Teammates' decisions on a review lesson, received from the team database (core team-decisions.ts): each with the
|
|
55
57
|
* teammate's display name and when the team database got it; and, when a later team decision settled the lesson
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* lesson's subject prefix). Counts that Rigour cannot know here are null, never 0: PR catches
|
|
8
8
|
* recorded on another machine (CI) never reach this one.
|
|
9
9
|
*/
|
|
10
|
-
import { acceptSuggestedText, scopeLesson, decideCompiledCheck, decideLesson, fixLessonPrefix, proposeCompiledChecks, readCompiledChecks, suspension, localOutcomeMetrics, pendingDecision, quietBotCandidate, listKnowledgeLessons, readLessons, lastDecision, readTeamDecisionCache } from '@rigour-labs/core';
|
|
10
|
+
import { acceptSuggestedText, scopeLesson, decideCompiledCheck, decideLesson, fixLessonPrefix, proposeCompiledChecks, readCompiledChecks, suspension, localOutcomeMetrics, pendingDecision, quietBotCandidate, listKnowledgeLessons, readLessons, lastDecision, takeBackable, readTeamDecisionCache } from '@rigour-labs/core';
|
|
11
11
|
import { decider } from './git-identity.js';
|
|
12
12
|
import { checkoutRoots, eventsAcross, storiesAcross } from './studio-checkouts.js';
|
|
13
13
|
const WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -53,6 +53,7 @@ export function buildLearning(input) {
|
|
|
53
53
|
...(l.suggestedText ? { suggestedText: { text: l.suggestedText, why: l.suggestedWhy ?? 'reworded' } } : {}),
|
|
54
54
|
reach: { scope: l.scope ?? 'file', hasFile: !!l.file },
|
|
55
55
|
...(quietBotCandidate(l) ? { fromBots: true } : {}),
|
|
56
|
+
...(takeBackable(l) ? { canTakeBack: true } : {}),
|
|
56
57
|
})),
|
|
57
58
|
// Lessons back to a candidate when outcomes stopped promoting come first: a person decides each once.
|
|
58
59
|
].sort((a, b) => Number(!!b.reclassified) - Number(!!a.reclassified) || b.learnedAt.localeCompare(a.learnedAt))
|
|
@@ -107,6 +108,7 @@ function decisionFor(lesson) {
|
|
|
107
108
|
function studioWhy(why) {
|
|
108
109
|
return typeof why === 'string' && why.trim() ? why.trim() : 'decided in Studio';
|
|
109
110
|
}
|
|
111
|
+
const REVIEW_DECISIONS = new Set(['accepted', 'rejected', 'dismissed', 'not-a-rule', 'took-back']);
|
|
110
112
|
/** A person's decision on a review lesson from Studio, recorded as `rigour learn-reviews --promote / --reject` records it: with their git email, and final. */
|
|
111
113
|
export function decideReviewLesson(cwd, body) {
|
|
112
114
|
const { id, decision, why } = (body ?? {});
|
|
@@ -116,8 +118,8 @@ export function decideReviewLesson(cwd, body) {
|
|
|
116
118
|
return rewordFromStudio(cwd, id);
|
|
117
119
|
if (decision === 'scope')
|
|
118
120
|
return scopeFromStudio(cwd, id, body.to, why);
|
|
119
|
-
if (decision
|
|
120
|
-
throw new Error('decision is accepted, rejected, dismissed, reworded or scope');
|
|
121
|
+
if (!REVIEW_DECISIONS.has(decision))
|
|
122
|
+
throw new Error('decision is accepted, rejected, dismissed, not-a-rule, took-back, reworded or scope');
|
|
121
123
|
const lesson = decideLesson(cwd, id, decision, decider(cwd), studioWhy(why));
|
|
122
124
|
if (!lesson)
|
|
123
125
|
throw new Error(`no review lesson ${id}`);
|
package/dist/commands/team.js
CHANGED
|
@@ -98,8 +98,14 @@ teamCommand
|
|
|
98
98
|
.description("Send queued lessons from the team's repositories, and your decisions on this repository's review lessons; receive the team's")
|
|
99
99
|
.option('--dry-run', 'Report pending records without sending them')
|
|
100
100
|
.action(async (options) => {
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
try {
|
|
102
|
+
console.log(JSON.stringify(await syncTeamOutbox({ dryRun: Boolean(options.dryRun), cwd: process.cwd() }), null, 2));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
// One line, with the fix when there is one; never the database driver's stack.
|
|
106
|
+
console.error(chalk.red(`Team sync failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
}
|
|
103
109
|
});
|
|
104
110
|
/** Initialize the schema, or print why it failed (with the fix) and set exit code 1. */
|
|
105
111
|
async function initializeSchemaOrReport(databaseUrl, pgvector) {
|
|
@@ -22,6 +22,7 @@ import fs from 'fs';
|
|
|
22
22
|
import path from 'path';
|
|
23
23
|
import { APPENDED_COMMENT } from './hooks-git.js';
|
|
24
24
|
import { disableHere, enabledHere, uninstallMachine } from './personal.js';
|
|
25
|
+
import { setReportOnlyHere } from './report-only.js';
|
|
25
26
|
import { isEmptyConfig, isRigourScript, readInstallRecord, unchangedSinceInstall, withoutRigour } from './install-record.js';
|
|
26
27
|
import { GITIGNORE_PATTERNS } from './init.js';
|
|
27
28
|
const CONFIGS = ['.claude/settings.json', '.cursor/hooks.json', '.windsurf/hooks.json', '.cursor/mcp.json', '.mcp.json'];
|
|
@@ -78,7 +79,7 @@ export function uninstall(cwd, options = {}) {
|
|
|
78
79
|
gitHook(cwd, act, report);
|
|
79
80
|
// A personal install: the switch inside the git directory (and its exclude line, with .rigour/ itself).
|
|
80
81
|
if (enabledHere(cwd))
|
|
81
|
-
act('switch Rigour off for this repository (personal install)', () => disableHere(cwd, !!options.all));
|
|
82
|
+
act('switch Rigour off for this repository (personal install)', () => { disableHere(cwd, !!options.all); setReportOnlyHere(cwd, false); });
|
|
82
83
|
else if (options.all && !options.dryRun)
|
|
83
84
|
disableHere(cwd, true);
|
|
84
85
|
if (options.machine)
|
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.11",
|
|
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.11"
|
|
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.11"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"build": "tsc && pnpm bundle-studio",
|