@nerviq/cli 1.17.1 → 1.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/cli.js +10 -1
- package/package.json +1 -1
- package/src/codex/context.js +2 -0
- package/src/codex/techniques.js +26 -7
package/README.md
CHANGED
package/bin/cli.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
// macOS pipe-flush guard: when stdout is a pipe, Node defaults to
|
|
2
|
+
// non-blocking writes. `console.log(...) + process.exit(N)` then drops
|
|
3
|
+
// the trailing write (empty stdout on macOS Node 18, truncation at the
|
|
4
|
+
// 8192-byte pipe buffer on macOS Node 20). Flipping stdout+stderr to
|
|
5
|
+
// blocking mode at the *very start* — before any writes queue up —
|
|
6
|
+
// makes every subsequent console.log a synchronous syscall, so the
|
|
7
|
+
// data is in the kernel before we ever reach process.exit. Runs before
|
|
8
|
+
// require() so it covers warnings from Node's module loader too.
|
|
9
|
+
try { if (process.stdout?._handle?.setBlocking) process.stdout._handle.setBlocking(true); } catch {}
|
|
10
|
+
try { if (process.stderr?._handle?.setBlocking) process.stderr._handle.setBlocking(true); } catch {}
|
|
2
11
|
|
|
3
12
|
const { audit, detectPlatforms, getCatalog } = require('../src/public-api');
|
|
4
13
|
const { setup } = require('../src/setup');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerviq/cli",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.3",
|
|
4
4
|
"description": "The intelligent nervous system for AI coding agents — 2,441 checks (8 platforms × ~300 governance rules), 10 languages, 62 domain packs. Audit, align, and amplify.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/codex/context.js
CHANGED
|
@@ -62,6 +62,8 @@ class CodexProjectContext extends ProjectContext {
|
|
|
62
62
|
|
|
63
63
|
agentsMdPath() {
|
|
64
64
|
if (this.fileContent('AGENTS.md')) return 'AGENTS.md';
|
|
65
|
+
// .codex/AGENTS.md is an emerging pattern (e.g., jessfraz/dotfiles)
|
|
66
|
+
if (this.fileContent('.codex/AGENTS.md')) return '.codex/AGENTS.md';
|
|
65
67
|
const fallbackNames = this.projectDocFallbackFilenames();
|
|
66
68
|
for (const fileName of fallbackNames) {
|
|
67
69
|
if (this.fileContent(fileName)) return fileName;
|
package/src/codex/techniques.js
CHANGED
|
@@ -173,7 +173,10 @@ function findFillerLine(content) {
|
|
|
173
173
|
|
|
174
174
|
function hasContradictions(content) {
|
|
175
175
|
const lines = content.split(/\r?\n/);
|
|
176
|
+
const lineEndingPattern = /\b(CRLF|LF|line[- ]ending|trailing newline|EOF|end.of.file|newline at end)\b/i;
|
|
176
177
|
for (const line of lines) {
|
|
178
|
+
// Skip line-ending/EOF style guidance — not actual contradictions
|
|
179
|
+
if (lineEndingPattern.test(line)) continue;
|
|
177
180
|
if (/\balways\b.*\bnever\b|\bnever\b.*\balways\b/i.test(line)) {
|
|
178
181
|
return true;
|
|
179
182
|
}
|
|
@@ -280,10 +283,20 @@ function unsupportedHookEvent(ctx) {
|
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
function hooksClaimed(ctx) {
|
|
286
|
+
// Strong signals: Codex-specific files/directories
|
|
283
287
|
if (ctx.hasDir('.codex/hooks')) return true;
|
|
284
288
|
if (ctx.hooksJsonContent && ctx.hooksJsonContent()) return true;
|
|
289
|
+
const config = ctx.fileContent('.codex/config.toml') || '';
|
|
290
|
+
if (/\[hooks\]|codex_hooks\s*=|\[features\][\s\S]*codex_hooks/i.test(config)) return true;
|
|
291
|
+
// Text signals: require Codex-specific hook terminology (not generic "hooks")
|
|
285
292
|
const content = agentsContent(ctx);
|
|
286
|
-
|
|
293
|
+
if (!content) return false;
|
|
294
|
+
// Specific Codex hook events — these are unambiguous
|
|
295
|
+
if (/\b(SessionStart|PreToolUse|PostToolUse|UserPromptSubmit)\b/.test(content)) return true;
|
|
296
|
+
// "Codex hooks" explicit mention
|
|
297
|
+
if (/\bcodex\s+hooks?\b/i.test(content)) return true;
|
|
298
|
+
if (/\bhooks?\.json\b/i.test(content) && /\bcodex\b/i.test(content)) return true;
|
|
299
|
+
return false;
|
|
287
300
|
}
|
|
288
301
|
|
|
289
302
|
function findSecretLine(content) {
|
|
@@ -1422,15 +1435,15 @@ function desktopProjectMcpCaveatIssue(ctx) {
|
|
|
1422
1435
|
const CODEX_TECHNIQUES = {
|
|
1423
1436
|
codexAgentsMd: {
|
|
1424
1437
|
id: 'CX-A01',
|
|
1425
|
-
name: 'AGENTS.md exists at project root',
|
|
1426
|
-
check: (ctx) => Boolean(ctx.fileContent('AGENTS.md')),
|
|
1438
|
+
name: 'AGENTS.md exists at project root or .codex/',
|
|
1439
|
+
check: (ctx) => Boolean(ctx.fileContent('AGENTS.md') || ctx.fileContent('.codex/AGENTS.md') || ctx.fileContent('.codex/agents.md')),
|
|
1427
1440
|
impact: 'critical',
|
|
1428
1441
|
rating: 5,
|
|
1429
1442
|
category: 'instructions',
|
|
1430
|
-
fix: 'Create AGENTS.md at the project root with repo-specific commands, trust guidance, and workflow expectations.',
|
|
1443
|
+
fix: 'Create AGENTS.md at the project root (or .codex/AGENTS.md) with repo-specific commands, trust guidance, and workflow expectations.',
|
|
1431
1444
|
template: 'codex-agents-md',
|
|
1432
|
-
file: () => 'AGENTS.md',
|
|
1433
|
-
line: (ctx) => (ctx.fileContent('AGENTS.md') ? 1 : null),
|
|
1445
|
+
file: (ctx) => ctx.fileContent('AGENTS.md') ? 'AGENTS.md' : (ctx.fileContent('.codex/AGENTS.md') ? '.codex/AGENTS.md' : 'AGENTS.md'),
|
|
1446
|
+
line: (ctx) => (ctx.fileContent('AGENTS.md') || ctx.fileContent('.codex/AGENTS.md') ? 1 : null),
|
|
1434
1447
|
},
|
|
1435
1448
|
codexAgentsMdSubstantive: {
|
|
1436
1449
|
id: 'CX-A02',
|
|
@@ -3111,8 +3124,14 @@ const CODEX_TECHNIQUES = {
|
|
|
3111
3124
|
'Gemfile', 'composer.json', 'pom.xml', 'build.gradle',
|
|
3112
3125
|
'flake.nix', 'shard.yml', 'mix.exs', 'rebar.config',
|
|
3113
3126
|
'Makefile', 'CMakeLists.txt', 'Package.swift', 'pubspec.yaml',
|
|
3127
|
+
// .NET ecosystem
|
|
3128
|
+
'Directory.Packages.props', 'Directory.Build.props', 'global.json',
|
|
3129
|
+
// Gradle wrapper
|
|
3130
|
+
'gradlew', 'gradlew.bat',
|
|
3114
3131
|
];
|
|
3115
|
-
const hasManifest = manifestFiles.some(f => ctx.files.includes(f))
|
|
3132
|
+
const hasManifest = manifestFiles.some(f => ctx.files.includes(f)) ||
|
|
3133
|
+
// .NET solution/project files use extensions — match by suffix
|
|
3134
|
+
ctx.files.some(f => /\.(sln|slnx|csproj|fsproj|vbproj)$/i.test(f));
|
|
3116
3135
|
// Dotfiles/config-only repos: they don't ship code, so pack recommendations
|
|
3117
3136
|
// aren't meaningful — N/A is the correct answer.
|
|
3118
3137
|
const dotfilesSignals = ['.zshrc', '.bashrc', '.vimrc', '.tmux.conf', '.gitconfig', 'install.sh', 'bootstrap.sh'];
|