@nerviq/cli 1.29.0 → 1.30.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +1764 -1493
  2. package/README.md +568 -538
  3. package/SECURITY.md +78 -82
  4. package/bin/cli.js +2838 -2558
  5. package/docs/api-reference.md +356 -356
  6. package/docs/audit-fix.md +109 -0
  7. package/docs/autofix.md +3 -62
  8. package/docs/getting-started.md +1 -1
  9. package/docs/index.html +592 -592
  10. package/docs/integration-contracts.md +287 -287
  11. package/docs/maintenance.md +128 -128
  12. package/docs/new-platform-guide.md +202 -202
  13. package/docs/release-process.md +63 -0
  14. package/docs/shallow-risk.md +244 -244
  15. package/docs/why-nerviq.md +82 -82
  16. package/package.json +75 -67
  17. package/sdk/README.md +12 -3
  18. package/sdk/examples/langchain-integration.md +128 -0
  19. package/sdk/examples/self-governing-agent.js +135 -0
  20. package/sdk/index.d.ts +115 -0
  21. package/sdk/index.js +94 -0
  22. package/sdk/package.json +11 -0
  23. package/src/activity.js +13 -0
  24. package/src/aider/activity.js +226 -226
  25. package/src/aider/context.js +162 -162
  26. package/src/aider/freshness.js +123 -123
  27. package/src/aider/techniques.js +3465 -3465
  28. package/src/audit/layers.js +180 -180
  29. package/src/audit.js +1133 -1032
  30. package/src/auto-suggest.js +9 -2
  31. package/src/behavioral-drift.js +37 -2
  32. package/src/benchmark.js +299 -299
  33. package/src/codex/activity.js +324 -324
  34. package/src/codex/freshness.js +149 -142
  35. package/src/codex/techniques.js +4895 -4895
  36. package/src/context.js +326 -326
  37. package/src/continuous-ops.js +11 -1
  38. package/src/convert.js +340 -340
  39. package/src/copilot/config-parser.js +280 -280
  40. package/src/copilot/context.js +218 -218
  41. package/src/copilot/freshness.js +184 -177
  42. package/src/copilot/patch.js +238 -238
  43. package/src/copilot/techniques.js +3578 -3578
  44. package/src/cursor/freshness.js +194 -194
  45. package/src/cursor/patch.js +243 -243
  46. package/src/cursor/techniques.js +3735 -3735
  47. package/src/doctor.js +201 -201
  48. package/src/fix-engine.js +511 -8
  49. package/src/formatters/csv.js +86 -86
  50. package/src/formatters/junit.js +123 -123
  51. package/src/formatters/markdown.js +164 -164
  52. package/src/formatters/otel.js +151 -151
  53. package/src/freshness.js +163 -156
  54. package/src/gemini/activity.js +402 -402
  55. package/src/gemini/context.js +290 -290
  56. package/src/gemini/freshness.js +188 -188
  57. package/src/gemini/patch.js +229 -229
  58. package/src/gemini/techniques.js +3811 -3811
  59. package/src/governance.js +533 -533
  60. package/src/harmony/audit.js +306 -306
  61. package/src/i18n.js +63 -63
  62. package/src/insights.js +119 -119
  63. package/src/integrations.js +134 -134
  64. package/src/locales/en.json +33 -33
  65. package/src/locales/es.json +33 -33
  66. package/src/migrate.js +354 -354
  67. package/src/opencode/activity.js +286 -286
  68. package/src/opencode/freshness.js +137 -137
  69. package/src/opencode/techniques.js +3450 -3450
  70. package/src/safe-glyph.js +97 -0
  71. package/src/setup/analysis.js +12 -12
  72. package/src/setup.js +13 -6
  73. package/src/shallow-risk/index.js +113 -56
  74. package/src/shallow-risk/patterns/agent-config-cross-platform-drift.js +51 -50
  75. package/src/shallow-risk/patterns/agent-config-dangerous-autoapprove.js +47 -46
  76. package/src/shallow-risk/patterns/agent-config-deprecated-keys.js +47 -46
  77. package/src/shallow-risk/patterns/agent-config-framework-version-mismatch.js +138 -0
  78. package/src/shallow-risk/patterns/agent-config-missing-file.js +318 -317
  79. package/src/shallow-risk/patterns/agent-config-script-not-in-package-json.js +108 -0
  80. package/src/shallow-risk/patterns/agent-config-secret-literal.js +52 -49
  81. package/src/shallow-risk/patterns/agent-config-stack-contradiction.js +35 -34
  82. package/src/shallow-risk/patterns/hook-script-missing.js +71 -70
  83. package/src/shallow-risk/patterns/mcp-server-no-allowlist.js +53 -52
  84. package/src/shallow-risk/shared.js +653 -648
  85. package/src/source-urls.js +295 -295
  86. package/src/state-paths.js +85 -85
  87. package/src/supplemental-checks.js +805 -805
  88. package/src/telemetry.js +160 -160
  89. package/src/watch.js +46 -0
  90. package/src/windsurf/context.js +359 -359
  91. package/src/windsurf/freshness.js +194 -194
  92. package/src/windsurf/patch.js +231 -231
  93. package/src/windsurf/techniques.js +3779 -3779
package/package.json CHANGED
@@ -1,67 +1,75 @@
1
- {
2
- "name": "@nerviq/cli",
3
- "version": "1.29.0",
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
- "main": "src/index.js",
6
- "bin": {
7
- "nerviq": "bin/cli.js",
8
- "@nerviq/cli": "bin/cli.js",
9
- "nerviq-mcp": "src/mcp-server.js"
10
- },
11
- "files": [
12
- "bin",
13
- "src",
14
- "README.md",
15
- "docs",
16
- "contracts",
17
- "sdk/README.md",
18
- "CHANGELOG.md",
19
- "SECURITY.md"
20
- ],
21
- "scripts": {
22
- "start": "node bin/cli.js",
23
- "build": "npm pack --dry-run",
24
- "test": "node test/run.js",
25
- "verify:release-metadata": "node tools/validate-release-metadata.js",
26
- "prepublish:check": "node tools/pre-publish.js",
27
- "prepublishOnly": "node tools/pre-publish.js",
28
- "test:jest": "jest",
29
- "test:coverage": "jest --coverage",
30
- "test:all": "npm test && npx jest && node test/check-matrix.js && node test/codex-check-matrix.js && node test/gemini-check-matrix.js && node test/copilot-check-matrix.js && node test/cursor-check-matrix.js && node test/windsurf-check-matrix.js && node test/aider-check-matrix.js && node test/opencode-check-matrix.js && node test/golden-matrix.js && node test/codex-golden-matrix.js && node test/gemini-golden-matrix.js && node test/copilot-golden-matrix.js && node test/cursor-golden-matrix.js && node test/windsurf-golden-matrix.js && node test/aider-golden-matrix.js && node test/opencode-golden-matrix.js",
31
- "benchmark:perf": "node tools/benchmark.js",
32
- "catalog": "node -e \"const {generateCatalog}=require('./src/catalog');console.log(JSON.stringify(generateCatalog(),null,2))\""
33
- },
34
- "keywords": [
35
- "nerviq",
36
- "ai-agents",
37
- "agent-governance",
38
- "agent-config",
39
- "harmony",
40
- "synergy",
41
- "audit",
42
- "claude",
43
- "codex",
44
- "gemini",
45
- "copilot",
46
- "cursor",
47
- "windsurf",
48
- "aider",
49
- "developer-tools",
50
- "cli",
51
- "mcp",
52
- "multi-agent"
53
- ],
54
- "author": "Nerviq <hello@nerviq.net>",
55
- "license": "AGPL-3.0",
56
- "repository": {
57
- "type": "git",
58
- "url": "git+https://github.com/nerviq/nerviq.git"
59
- },
60
- "homepage": "https://nerviq.net",
61
- "engines": {
62
- "node": ">=18.0.0"
63
- },
64
- "devDependencies": {
65
- "jest": "^30.3.0"
66
- }
67
- }
1
+ {
2
+ "name": "@nerviq/cli",
3
+ "version": "1.30.0",
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
+ "main": "src/index.js",
6
+ "exports": {
7
+ ".": "./src/index.js",
8
+ "./sdk": "./sdk/index.js",
9
+ "./sdk/types": "./sdk/index.d.ts",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "bin": {
13
+ "nerviq": "bin/cli.js",
14
+ "@nerviq/cli": "bin/cli.js",
15
+ "nerviq-mcp": "src/mcp-server.js"
16
+ },
17
+ "files": [
18
+ "bin",
19
+ "src",
20
+ "sdk",
21
+ "README.md",
22
+ "docs",
23
+ "contracts",
24
+ "CHANGELOG.md",
25
+ "SECURITY.md"
26
+ ],
27
+ "scripts": {
28
+ "start": "node bin/cli.js",
29
+ "build": "npm pack --dry-run",
30
+ "test": "node test/run.js",
31
+ "verify:release-metadata": "node tools/validate-release-metadata.js",
32
+ "prepublish:check": "node tools/pre-publish.js",
33
+ "prepublishOnly": "node tools/pre-publish.js",
34
+ "postinstall": "node tools/postinstall.js || true",
35
+ "test:jest": "jest",
36
+ "test:coverage": "jest --coverage",
37
+ "test:all": "npm test && npx jest && node test/check-matrix.js && node test/codex-check-matrix.js && node test/gemini-check-matrix.js && node test/copilot-check-matrix.js && node test/cursor-check-matrix.js && node test/windsurf-check-matrix.js && node test/aider-check-matrix.js && node test/opencode-check-matrix.js && node test/golden-matrix.js && node test/codex-golden-matrix.js && node test/gemini-golden-matrix.js && node test/copilot-golden-matrix.js && node test/cursor-golden-matrix.js && node test/windsurf-golden-matrix.js && node test/aider-golden-matrix.js && node test/opencode-golden-matrix.js",
38
+ "benchmark:perf": "node tools/benchmark.js",
39
+ "announce:release": "node tools/announce-release.js",
40
+ "catalog": "node -e \"const {generateCatalog}=require('./src/catalog');console.log(JSON.stringify(generateCatalog(),null,2))\""
41
+ },
42
+ "keywords": [
43
+ "nerviq",
44
+ "ai-agents",
45
+ "agent-governance",
46
+ "agent-config",
47
+ "harmony",
48
+ "synergy",
49
+ "audit",
50
+ "claude",
51
+ "codex",
52
+ "gemini",
53
+ "copilot",
54
+ "cursor",
55
+ "windsurf",
56
+ "aider",
57
+ "developer-tools",
58
+ "cli",
59
+ "mcp",
60
+ "multi-agent"
61
+ ],
62
+ "author": "Nerviq <hello@nerviq.net>",
63
+ "license": "AGPL-3.0",
64
+ "repository": {
65
+ "type": "git",
66
+ "url": "git+https://github.com/nerviq/nerviq.git"
67
+ },
68
+ "homepage": "https://nerviq.net",
69
+ "engines": {
70
+ "node": ">=18.0.0"
71
+ },
72
+ "devDependencies": {
73
+ "jest": "^30.3.0"
74
+ }
75
+ }
package/sdk/README.md CHANGED
@@ -1,13 +1,22 @@
1
- # @nerviq/sdk
1
+ # Nerviq SDK (bundled inside `@nerviq/cli`)
2
2
 
3
3
  Programmatic SDK for Nerviq audit, Harmony, catalog access, and experimental Synergy workflows.
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- npm install @nerviq/sdk
8
+ npm install @nerviq/cli
9
9
  ```
10
10
 
11
+ The SDK ships bundled inside `@nerviq/cli` per MEMO-03 (B = BUNDLE, signed 2026-04-28). There is no separate `@nerviq/sdk` npm package — earlier docs that referenced one were aspirational. Both import paths below work:
12
+
13
+ ```js
14
+ const sdk = require('@nerviq/cli/sdk'); // explicit SDK subpath (typed, input-validated)
15
+ const { audit } = require('@nerviq/cli'); // top-level — same exports
16
+ ```
17
+
18
+ The two paths return identical surface; pick whichever is cleaner for your codebase.
19
+
11
20
  ## Stability
12
21
 
13
22
  - Stable for production workflows: `audit`, `harmonyAudit`, `detectPlatforms`, `getCatalog`
@@ -17,7 +26,7 @@ npm install @nerviq/sdk
17
26
  ## Quick Start
18
27
 
19
28
  ```js
20
- const { audit, harmonyAudit, detectPlatforms } = require('@nerviq/sdk');
29
+ const { audit, harmonyAudit, detectPlatforms } = require('@nerviq/cli/sdk');
21
30
 
22
31
  async function main() {
23
32
  const repoDir = process.cwd();
@@ -0,0 +1,128 @@
1
+ # LangChain integration — using Nerviq as a tool
2
+
3
+ > Reference example for AI-09. Wires `@nerviq/cli/sdk` into a LangChain
4
+ > agent as a callable tool, so an autonomous LangChain agent can audit
5
+ > its own repo, check Harmony Score, and surface stale references mid-task.
6
+ >
7
+ > Pairs with: [`self-governing-agent.js`](./self-governing-agent.js) +
8
+ > [/docs/for-agents](https://nerviq.net/docs/for-agents) on the site.
9
+
10
+ ## Why an agent should call Nerviq
11
+
12
+ A LangChain agent operating inside a developer's repo benefits from knowing whether the agent-config files it's reading are coherent across platforms. Without that awareness, the agent can confidently follow instructions in `CLAUDE.md` that contradict instructions in `AGENTS.md` — and produce code that breaks in someone else's tooling.
13
+
14
+ Wiring Nerviq as a LangChain tool exposes three primitives:
15
+
16
+ - `nerviq_audit` — score the repo on a specific platform
17
+ - `nerviq_harmony` — measure cross-platform drift
18
+ - `nerviq_stale_references` — surface the headline stale-reference findings
19
+
20
+ ## JavaScript / Node example
21
+
22
+ ```js
23
+ const { audit, harmonyAudit } = require('@nerviq/cli/sdk');
24
+ const { DynamicTool } = require('@langchain/core/tools');
25
+
26
+ const nerviqAuditTool = new DynamicTool({
27
+ name: 'nerviq_audit',
28
+ description:
29
+ 'Audit the AI coding agent configuration of the given repo directory. ' +
30
+ 'Returns score (0-100), passed/failed counts, top stale-reference findings, ' +
31
+ 'and topNextActions. Call this before substantive code changes when the ' +
32
+ 'task touches CLAUDE.md, AGENTS.md, .cursor/rules, .mcp.json, or hooks.',
33
+ func: async (dir) => {
34
+ const result = await audit(dir || process.cwd(), 'claude');
35
+ return JSON.stringify({
36
+ score: result.score,
37
+ organicScore: result.organicScore,
38
+ passed: result.passed,
39
+ failed: result.failed,
40
+ staleReferences: result.staleReferences || null,
41
+ topNextActions: (result.liteSummary && result.liteSummary.topNextActions) || [],
42
+ }, null, 2);
43
+ },
44
+ });
45
+
46
+ const nerviqHarmonyTool = new DynamicTool({
47
+ name: 'nerviq_harmony',
48
+ description:
49
+ 'Measure cross-platform configuration drift between AI coding agents in ' +
50
+ 'the given repo. Returns harmonyScore (0-100) plus a list of named ' +
51
+ 'drifts. Only meaningful when 2+ platforms are detected.',
52
+ func: async (dir) => {
53
+ const result = await harmonyAudit(dir || process.cwd());
54
+ return JSON.stringify({
55
+ harmonyScore: result.harmonyScore,
56
+ activePlatforms: result.activePlatforms,
57
+ drifts: (result.drift && result.drift.drifts) || [],
58
+ }, null, 2);
59
+ },
60
+ });
61
+
62
+ // Add to your agent's tool list:
63
+ const tools = [nerviqAuditTool, nerviqHarmonyTool /*, ...your other tools */];
64
+ ```
65
+
66
+ ## Python via subprocess
67
+
68
+ LangChain agents in Python can shell out to the CLI's `--agent-mode --json` surface:
69
+
70
+ ```python
71
+ from langchain_core.tools import tool
72
+ import json
73
+ import subprocess
74
+
75
+ @tool
76
+ def nerviq_audit(dir: str = ".") -> str:
77
+ """Audit AI coding agent configuration. Returns score, stale references,
78
+ top next actions. Call before substantive code changes."""
79
+ result = subprocess.run(
80
+ ["npx", "@nerviq/cli", "audit", "--json", "--agent-mode", "--dir", dir],
81
+ capture_output=True, text=True, timeout=60,
82
+ )
83
+ if result.returncode not in (0, 1, 2):
84
+ return json.dumps({"error": result.stderr})
85
+ return result.stdout # Already JSON
86
+ ```
87
+
88
+ ## CrewAI / AutoGen / generic orchestrators
89
+
90
+ Same pattern: any orchestrator that supports tool definitions can wrap the SDK or shell out to `npx @nerviq/cli audit --json`. The JSON envelope is documented at [/docs/for-agents](https://nerviq.net/docs/for-agents) and stable per CTO-01..05 + BUG-01 (machine-output contract).
91
+
92
+ For CrewAI specifically:
93
+
94
+ ```python
95
+ from crewai.tools import tool
96
+ import subprocess
97
+
98
+ @tool("Nerviq audit tool")
99
+ def nerviq_audit(dir: str = "."):
100
+ """Audit cross-platform AI coding agent configuration."""
101
+ out = subprocess.run(
102
+ ["npx", "@nerviq/cli", "audit", "--json", "--dir", dir],
103
+ capture_output=True, text=True, timeout=60,
104
+ ).stdout
105
+ return out
106
+ ```
107
+
108
+ ## Don't bypass user consent
109
+
110
+ Per the [/docs/for-agents](https://nerviq.net/docs/for-agents) trust-boundary policy: the agent should NOT silently apply `--apply --auto` on critical fixes that materially modify governance posture (deny rules, MCP permissions, hooks). Surface the plan via the audit/harmony tool, let the user approve, then apply. The CLI gates `--apply` on `--auto` for exactly this reason — single-flag bypass is intentionally blocked.
111
+
112
+ ## When to call which tool
113
+
114
+ | Situation | Call |
115
+ |---|---|
116
+ | Task start | `nerviq_audit` (always) |
117
+ | Task touches multiple agents' config | `nerviq_harmony` (drift check) |
118
+ | Stale-reference count > 0 in audit result | Surface to user via the audit response, ask whether to proceed |
119
+ | Task complete | `nerviq_audit` again, compare scores, surface delta to user |
120
+ | User accepts a recommendation | (Optionally) record via `npx @nerviq/cli feedback --key <K> --status accepted` so the local learning loop benefits |
121
+
122
+ ## Reference repo
123
+
124
+ The full self-governing loop reference (5-step pre/harmony/task/post/feedback pattern) lives at [`sdk/examples/self-governing-agent.js`](./self-governing-agent.js). Read that first if you're implementing the orchestration manually rather than letting LangChain/CrewAI drive the loop.
125
+
126
+ ## License
127
+
128
+ CC0 — copy, modify, integrate freely.
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Reference: self-governing AI coding agent loop using @nerviq/cli/sdk.
4
+ *
5
+ * This file is the AI-07 reference example for the docs/for-agents page on
6
+ * nerviq.net. It implements the "Self-governing agent pattern" documented
7
+ * there: an agent that audits the repo before acting, runs targeted fixes,
8
+ * makes the actual code change, re-audits to detect regression, and records
9
+ * outcomes back into the local learning loop.
10
+ *
11
+ * Usage (after `npm install @nerviq/cli`):
12
+ * node node_modules/@nerviq/cli/sdk/examples/self-governing-agent.js [repo-dir]
13
+ *
14
+ * Default repo-dir is process.cwd().
15
+ *
16
+ * NOT autonomous in the dangerous sense:
17
+ * - This loop NEVER calls --apply --auto silently. Mutations of governance
18
+ * posture (deny rules, MCP permissions, hooks) require explicit user
19
+ * consent. The example surfaces a plan and waits for the next human
20
+ * decision; that's by design and matches the docs/for-agents constraint.
21
+ */
22
+
23
+ 'use strict';
24
+
25
+ // Resolve the SDK from npm install OR from the in-repo path (for running this
26
+ // example directly from a checkout of nerviq/nerviq).
27
+ function loadSdk() {
28
+ try {
29
+ return require('@nerviq/cli/sdk');
30
+ } catch {
31
+ return require('../index.js');
32
+ }
33
+ }
34
+ const { audit, harmonyAudit, detectPlatforms } = loadSdk();
35
+ const path = require('path');
36
+
37
+ async function selfGoverningLoop(repoDir, opts = {}) {
38
+ const dir = path.resolve(repoDir);
39
+ const log = opts.log || console.log;
40
+ const HARMONY_DRIFT_THRESHOLD = 60;
41
+
42
+ // ── Step 1. Pre-task audit ──────────────────────────────────────────────
43
+ log('[1/5] pre-task audit…');
44
+ const platforms = detectPlatforms(dir);
45
+ log(` platforms: ${platforms.join(', ') || '(none detected — single-platform repo)'}`);
46
+
47
+ const pre = await audit(dir, opts.platform || (platforms[0] || 'claude'));
48
+ log(` score: ${pre.score}/100 organic: ${pre.organicScore}/100 failed: ${pre.failed}`);
49
+
50
+ // The headline value: stale references. Surface BEFORE doing anything.
51
+ if (pre.staleReferences && pre.staleReferences.count > 0) {
52
+ log(` 📌 ${pre.staleReferences.headline}`);
53
+ for (const sample of pre.staleReferences.topSample) {
54
+ log(` · ${sample.file}:${sample.line} — ${sample.fix.split('\n')[0].slice(0, 100)}`);
55
+ }
56
+ log(' ↳ recommend: surface to user, ask whether to proceed despite stale refs');
57
+ }
58
+
59
+ // ── Step 2. Cross-platform Harmony check (only if multi-platform) ──────
60
+ if (platforms.length >= 2) {
61
+ log('[2/5] harmony check (cross-platform drift)…');
62
+ const harmony = await harmonyAudit(dir);
63
+ log(` harmonyScore: ${harmony.harmonyScore}/100`);
64
+
65
+ if (harmony.harmonyScore < HARMONY_DRIFT_THRESHOLD) {
66
+ log(` ⚠️ harmony below ${HARMONY_DRIFT_THRESHOLD} — drift between platforms is forming`);
67
+ log(' ↳ recommend: surface drifts to user, decide whether to harmony-sync before proceeding');
68
+ // NOTE: a real agent would surface harmony.drift list here and wait for
69
+ // user approval before running `nerviq harmony-sync --fix`. We do NOT
70
+ // call it silently from the agent loop.
71
+ }
72
+ } else {
73
+ log('[2/5] harmony check skipped (single-platform repo)');
74
+ }
75
+
76
+ // ── Step 3. Make the actual code change ─────────────────────────────────
77
+ log('[3/5] doing the actual task… (placeholder — replace with the real agent action)');
78
+ // In a real agent: execute the user's task. Edit files, run tests, etc.
79
+ // For this example, simulate a small change so step 4's diff-only audit has
80
+ // something to compare against.
81
+ if (typeof opts.doWork === 'function') {
82
+ await opts.doWork({ dir, preAuditScore: pre.score });
83
+ } else {
84
+ log(' (no doWork callback provided — skipping)');
85
+ }
86
+
87
+ // ── Step 4. Post-task diff-only re-audit ────────────────────────────────
88
+ log('[4/5] post-task diff-only audit…');
89
+ const post = await audit(dir, opts.platform || (platforms[0] || 'claude'));
90
+ const delta = post.score - pre.score;
91
+ const arrow = delta > 0 ? `+${delta}` : delta < 0 ? `${delta}` : '0';
92
+ log(` score: ${post.score}/100 Δ ${arrow} failed: ${post.failed}`);
93
+
94
+ if (delta < -3) {
95
+ log(' 🔴 score dropped materially — recommend: rollback or human review');
96
+ } else if (delta > 0) {
97
+ log(' ✓ score improved');
98
+ }
99
+
100
+ // ── Step 5. Record outcome (learning loop) ─────────────────────────────
101
+ log('[5/5] outcome recording — call `nerviq feedback --key <K> --status accepted|rejected|deferred --score-delta <delta>`');
102
+ log(' (the agent should invoke this once per recommendation it acted on, so suggest-rules can learn the team\'s actual preferences)');
103
+
104
+ return {
105
+ pre,
106
+ post,
107
+ delta,
108
+ platforms,
109
+ recommendation:
110
+ delta < -3
111
+ ? 'rollback-or-review'
112
+ : pre.staleReferences && pre.staleReferences.count > 0
113
+ ? 'surface-stale-references-to-user'
114
+ : delta > 0
115
+ ? 'continue'
116
+ : 'no-change',
117
+ };
118
+ }
119
+
120
+ if (require.main === module) {
121
+ const dir = process.argv[2] || process.cwd();
122
+ selfGoverningLoop(dir, { log: console.log })
123
+ .then((result) => {
124
+ console.log('\n=== Loop complete ===');
125
+ console.log(`Recommendation: ${result.recommendation}`);
126
+ console.log(`Pre/post score: ${result.pre.score} → ${result.post.score} (Δ ${result.delta})`);
127
+ process.exitCode = result.recommendation === 'rollback-or-review' ? 1 : 0;
128
+ })
129
+ .catch((err) => {
130
+ console.error(`error: ${err.message}`);
131
+ process.exitCode = 1;
132
+ });
133
+ }
134
+
135
+ module.exports = { selfGoverningLoop };
package/sdk/index.d.ts ADDED
@@ -0,0 +1,115 @@
1
+ export type NerviqPlatform =
2
+ | 'claude'
3
+ | 'codex'
4
+ | 'gemini'
5
+ | 'copilot'
6
+ | 'cursor'
7
+ | 'windsurf'
8
+ | 'aider'
9
+ | 'opencode';
10
+
11
+ export interface AuditFinding {
12
+ key: string;
13
+ id?: string | null;
14
+ name: string;
15
+ category?: string | null;
16
+ impact?: 'critical' | 'high' | 'medium' | 'low' | null;
17
+ fix?: string | null;
18
+ passed: boolean | null;
19
+ file?: string | null;
20
+ line?: number | null;
21
+ sourceUrl?: string | null;
22
+ confidence?: number | string | null;
23
+ }
24
+
25
+ export interface AuditAction {
26
+ key: string;
27
+ id?: string | null;
28
+ name: string;
29
+ impact?: 'critical' | 'high' | 'medium' | 'low' | null;
30
+ category?: string | null;
31
+ fix?: string | null;
32
+ why?: string | null;
33
+ sourceUrl?: string | null;
34
+ }
35
+
36
+ export interface AuditResult {
37
+ platform: string;
38
+ platformLabel: string;
39
+ score: number;
40
+ passed: number;
41
+ failed: number;
42
+ skipped: number;
43
+ checkCount: number;
44
+ results: AuditFinding[];
45
+ quickWins: AuditAction[];
46
+ topNextActions: AuditAction[];
47
+ suggestedNextCommand?: string;
48
+ /** Convenience alias for `passed` */
49
+ passing: number;
50
+ /** Convenience alias for `passed + failed` */
51
+ total: number;
52
+ }
53
+
54
+ export interface HarmonyResult {
55
+ harmonyScore: number;
56
+ platformScores: Record<string, number | null>;
57
+ platformResults: Record<string, AuditResult | null>;
58
+ drift: {
59
+ drifts: Array<Record<string, unknown>>;
60
+ harmonyScore: number;
61
+ };
62
+ recommendations: Array<Record<string, unknown>>;
63
+ activePlatforms: Array<Record<string, unknown>>;
64
+ model: Record<string, unknown>;
65
+ /** Convenience alias for `harmonyScore` */
66
+ average: number;
67
+ }
68
+
69
+ export interface Check {
70
+ platform: string;
71
+ id: string | null;
72
+ key: string;
73
+ name: string | null;
74
+ category: string | null;
75
+ impact: string | null;
76
+ rating: string | null;
77
+ fix: string | null;
78
+ sourceUrl: string | null;
79
+ confidence: number | null;
80
+ lastVerified?: string | null;
81
+ template?: string | null;
82
+ deprecated?: boolean;
83
+ }
84
+
85
+ export interface RoutingChoice {
86
+ platform: string;
87
+ confidence: number;
88
+ reasoning: string;
89
+ }
90
+
91
+ export interface RoutingResult {
92
+ recommended: RoutingChoice | null;
93
+ alternatives: RoutingChoice[];
94
+ taskType: string;
95
+ }
96
+
97
+ export interface SynergyResult {
98
+ dir: string;
99
+ activePlatforms: string[];
100
+ platformAudits: Record<string, AuditResult>;
101
+ compound: Record<string, unknown>;
102
+ amplification: number;
103
+ compensation: Record<string, unknown>;
104
+ patterns: Array<Record<string, unknown>>;
105
+ recommendations: Array<Record<string, unknown>>;
106
+ errors: Array<{ platform: string; message: string }>;
107
+ report: string;
108
+ }
109
+
110
+ export declare function audit(dir: string, platform?: NerviqPlatform): Promise<AuditResult>;
111
+ export declare function harmonyAudit(dir: string): Promise<HarmonyResult>;
112
+ export declare function synergyReport(dir: string): Promise<SynergyResult>;
113
+ export declare function detectPlatforms(dir: string): string[];
114
+ export declare function getCatalog(): Check[];
115
+ export declare function routeTask(description: string, platforms?: string[]): RoutingResult;
package/sdk/index.js ADDED
@@ -0,0 +1,94 @@
1
+ const path = require('path');
2
+ const fs = require('fs');
3
+
4
+ const VALID_PLATFORMS = ['claude', 'codex', 'cursor', 'copilot', 'gemini', 'windsurf', 'aider', 'opencode'];
5
+
6
+ function loadCore() {
7
+ try {
8
+ return require('@nerviq/cli');
9
+ } catch {
10
+ return require('..');
11
+ }
12
+ }
13
+
14
+ function validateDir(dir) {
15
+ if (!dir || typeof dir !== 'string') {
16
+ throw new Error('dir is required and must be a string. Pass a valid directory path.');
17
+ }
18
+ const resolved = path.resolve(dir);
19
+ if (!fs.existsSync(resolved)) {
20
+ throw new Error(`Directory not found: ${resolved}. Pass an existing directory path.`);
21
+ }
22
+ return resolved;
23
+ }
24
+
25
+ function validatePlatform(platform) {
26
+ if (platform && !VALID_PLATFORMS.includes(platform)) {
27
+ throw new Error(`Unsupported platform '${platform}'. Use one of: ${VALID_PLATFORMS.join(', ')}`);
28
+ }
29
+ }
30
+
31
+ async function audit(dir, platform = 'claude') {
32
+ const resolved = validateDir(dir);
33
+ validatePlatform(platform);
34
+ const core = loadCore();
35
+ const result = await core.audit({
36
+ dir: resolved,
37
+ platform,
38
+ silent: true,
39
+ });
40
+ // Add convenience aliases for SDK consumers
41
+ if (result) {
42
+ result.passing = result.passed;
43
+ result.total = (result.passed || 0) + (result.failed || 0);
44
+ }
45
+ return result;
46
+ }
47
+
48
+ async function harmonyAudit(dir) {
49
+ const resolved = validateDir(dir);
50
+ const core = loadCore();
51
+ const result = await core.harmonyAudit({
52
+ dir: resolved,
53
+ silent: true,
54
+ });
55
+ // Add convenience alias for SDK consumers
56
+ if (result) {
57
+ result.average = result.harmonyScore;
58
+ }
59
+ return result;
60
+ }
61
+
62
+ async function synergyReport(dir) {
63
+ const resolved = validateDir(dir);
64
+ const core = loadCore();
65
+ return core.synergyReport(resolved);
66
+ }
67
+
68
+ function detectPlatforms(dir) {
69
+ const resolved = validateDir(dir);
70
+ const core = loadCore();
71
+ return core.detectPlatforms(resolved);
72
+ }
73
+
74
+ function getCatalog() {
75
+ const core = loadCore();
76
+ return core.getCatalog();
77
+ }
78
+
79
+ function routeTask(description, platforms) {
80
+ if (!description || typeof description !== 'string') {
81
+ throw new Error('description is required and must be a non-empty string.');
82
+ }
83
+ const core = loadCore();
84
+ return core.routeTask(description, platforms || []);
85
+ }
86
+
87
+ module.exports = {
88
+ audit,
89
+ harmonyAudit,
90
+ synergyReport,
91
+ detectPlatforms,
92
+ getCatalog,
93
+ routeTask,
94
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "@nerviq/sdk",
3
+ "version": "0.9.5",
4
+ "main": "index.js",
5
+ "types": "index.d.ts",
6
+ "description": "Programmatic SDK for Nerviq — audit, harmony, synergy for AI coding agents",
7
+ "license": "AGPL-3.0",
8
+ "dependencies": {
9
+ "@nerviq/cli": "^0.9.5"
10
+ }
11
+ }