@nerviq/cli 1.2.0 → 1.2.2
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/LICENSE +19 -17
- package/package.json +2 -2
- package/src/aider/techniques.js +25 -24
- package/src/cursor/techniques.js +25 -24
- package/src/opencode/techniques.js +25 -24
- package/src/supplemental-checks.js +817 -767
- package/src/windsurf/techniques.js +25 -24
|
@@ -25,6 +25,7 @@ const path = require('path');
|
|
|
25
25
|
const { EMBEDDED_SECRET_PATTERNS, containsEmbeddedSecret } = require('../secret-patterns');
|
|
26
26
|
const { attachSourceUrls } = require('../source-urls');
|
|
27
27
|
const { buildStackChecks } = require('../stack-checks');
|
|
28
|
+
const { isApiProject, isDatabaseProject, isAuthProject, isMonitoringRelevant } = require('../supplemental-checks');
|
|
28
29
|
|
|
29
30
|
const DEFAULT_PROJECT_DOC_MAX_BYTES = 32768;
|
|
30
31
|
|
|
@@ -1770,168 +1771,168 @@ const OPENCODE_TECHNIQUES = {
|
|
|
1770
1771
|
},
|
|
1771
1772
|
ocEndpointDocumentation: {
|
|
1772
1773
|
id: 'OC-T13', name: 'API endpoint documentation present',
|
|
1773
|
-
check: (ctx) => ctx.files.some(f => /openapi|swagger|api\.ya?ml|api\.json/i.test(f)),
|
|
1774
|
+
check: (ctx) => !isApiProject(ctx) ? null : ctx.files.some(f => /openapi|swagger|api\.ya?ml|api\.json/i.test(f)),
|
|
1774
1775
|
impact: 'medium', rating: 3, category: 'api-design',
|
|
1775
1776
|
fix: 'Add OpenAPI/Swagger spec for OpenCode to understand the API.',
|
|
1776
1777
|
template: null, file: () => null, line: () => null,
|
|
1777
1778
|
},
|
|
1778
1779
|
ocApiVersioningMentioned: {
|
|
1779
1780
|
id: 'OC-T14', name: 'API versioning strategy documented',
|
|
1780
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /api.{0,10}version|\/v\d|versioning/i.test(docs); },
|
|
1781
|
+
check: (ctx) => { if (!isApiProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /api.{0,10}version|\/v\d|versioning/i.test(docs); },
|
|
1781
1782
|
impact: 'medium', rating: 3, category: 'api-design',
|
|
1782
1783
|
fix: 'Document API versioning strategy in AGENTS.md.',
|
|
1783
1784
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1784
1785
|
},
|
|
1785
1786
|
ocErrorHandlingPatterns: {
|
|
1786
1787
|
id: 'OC-T15', name: 'Error handling patterns documented',
|
|
1787
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /error.{0,15}handl|exception|try.?catch|Result\s*</i.test(docs); },
|
|
1788
|
+
check: (ctx) => { if (!isApiProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /error.{0,15}handl|exception|try.?catch|Result\s*</i.test(docs); },
|
|
1788
1789
|
impact: 'high', rating: 4, category: 'api-design',
|
|
1789
1790
|
fix: 'Document error handling patterns in AGENTS.md.',
|
|
1790
1791
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1791
1792
|
},
|
|
1792
1793
|
ocRateLimitingAwareness: {
|
|
1793
1794
|
id: 'OC-T16', name: 'Rate limiting awareness documented',
|
|
1794
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rate.?limit|throttl|429/i.test(docs); },
|
|
1795
|
+
check: (ctx) => { if (!isApiProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rate.?limit|throttl|429/i.test(docs); },
|
|
1795
1796
|
impact: 'medium', rating: 3, category: 'api-design',
|
|
1796
1797
|
fix: 'Document rate limiting in AGENTS.md.',
|
|
1797
1798
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1798
1799
|
},
|
|
1799
1800
|
ocRequestValidation: {
|
|
1800
1801
|
id: 'OC-T17', name: 'Request validation strategy documented',
|
|
1801
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /validat|zod|yup|joi\b/i.test(docs); },
|
|
1802
|
+
check: (ctx) => { if (!isApiProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /validat|zod|yup|joi\b/i.test(docs); },
|
|
1802
1803
|
impact: 'high', rating: 4, category: 'api-design',
|
|
1803
1804
|
fix: 'Document request validation library (Zod, Yup) in AGENTS.md.',
|
|
1804
1805
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1805
1806
|
},
|
|
1806
1807
|
ocResponseFormatConsistent: {
|
|
1807
1808
|
id: 'OC-T18', name: 'Response format consistency documented',
|
|
1808
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /response.{0,20}format|json.{0,10}response|envelope/i.test(docs); },
|
|
1809
|
+
check: (ctx) => { if (!isApiProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /response.{0,20}format|json.{0,10}response|envelope/i.test(docs); },
|
|
1809
1810
|
impact: 'medium', rating: 3, category: 'api-design',
|
|
1810
1811
|
fix: 'Document standard response format in AGENTS.md.',
|
|
1811
1812
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1812
1813
|
},
|
|
1813
1814
|
ocMigrationStrategyDocumented: {
|
|
1814
1815
|
id: 'OC-T19', name: 'Database migration strategy documented',
|
|
1815
|
-
check: (ctx) => ctx.files.some(f => /migrations?\//i.test(f)) || /migration|alembic|flyway/i.test(docsBundle(ctx)),
|
|
1816
|
+
check: (ctx) => !isDatabaseProject(ctx) ? null : ctx.files.some(f => /migrations?\//i.test(f)) || /migration|alembic|flyway/i.test(docsBundle(ctx)),
|
|
1816
1817
|
impact: 'high', rating: 4, category: 'database',
|
|
1817
1818
|
fix: 'Document migration strategy in AGENTS.md.',
|
|
1818
1819
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1819
1820
|
},
|
|
1820
1821
|
ocQueryOptimizationMentioned: {
|
|
1821
1822
|
id: 'OC-T20', name: 'Query optimization guidance documented',
|
|
1822
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /n\+1|query.{0,15}optim|index|eager.{0,10}load/i.test(docs); },
|
|
1823
|
+
check: (ctx) => { if (!isDatabaseProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /n\+1|query.{0,15}optim|index|eager.{0,10}load/i.test(docs); },
|
|
1823
1824
|
impact: 'medium', rating: 3, category: 'database',
|
|
1824
1825
|
fix: 'Add N+1 prevention patterns to AGENTS.md.',
|
|
1825
1826
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1826
1827
|
},
|
|
1827
1828
|
ocConnectionPoolingConfigured: {
|
|
1828
1829
|
id: 'OC-T21', name: 'Connection pooling documented',
|
|
1829
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /connection.{0,15}pool|pool.{0,15}size/i.test(docs); },
|
|
1830
|
+
check: (ctx) => { if (!isDatabaseProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /connection.{0,15}pool|pool.{0,15}size/i.test(docs); },
|
|
1830
1831
|
impact: 'medium', rating: 3, category: 'database',
|
|
1831
1832
|
fix: 'Document connection pooling in AGENTS.md.',
|
|
1832
1833
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1833
1834
|
},
|
|
1834
1835
|
ocBackupStrategyDocumented: {
|
|
1835
1836
|
id: 'OC-T22', name: 'Database backup strategy documented',
|
|
1836
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /backup|restore|point.?in.?time/i.test(docs); },
|
|
1837
|
+
check: (ctx) => { if (!isDatabaseProject(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /backup|restore|point.?in.?time/i.test(docs); },
|
|
1837
1838
|
impact: 'medium', rating: 3, category: 'database',
|
|
1838
1839
|
fix: 'Document database backup strategy in README.md.',
|
|
1839
1840
|
template: null, file: () => 'README.md', line: () => null,
|
|
1840
1841
|
},
|
|
1841
1842
|
ocSchemaDocumentation: {
|
|
1842
1843
|
id: 'OC-T23', name: 'Database schema documentation present',
|
|
1843
|
-
check: (ctx) => ctx.files.some(f => /schema\.(prisma|sql|graphql)|erd|dbml/i.test(f)),
|
|
1844
|
+
check: (ctx) => !isDatabaseProject(ctx) ? null : ctx.files.some(f => /schema\.(prisma|sql|graphql)|erd|dbml/i.test(f)),
|
|
1844
1845
|
impact: 'medium', rating: 3, category: 'database',
|
|
1845
1846
|
fix: 'Add schema documentation (schema.prisma, ERD) for OpenCode.',
|
|
1846
1847
|
template: null, file: () => null, line: () => null,
|
|
1847
1848
|
},
|
|
1848
1849
|
ocSeedDataMentioned: {
|
|
1849
1850
|
id: 'OC-T24', name: 'Seed data strategy documented',
|
|
1850
|
-
check: (ctx) => ctx.files.some(f => /seed\.(ts|js|sql|py)|fixtures\//i.test(f)) || /seed.{0,10}data/i.test(docsBundle(ctx)),
|
|
1851
|
+
check: (ctx) => !isDatabaseProject(ctx) ? null : ctx.files.some(f => /seed\.(ts|js|sql|py)|fixtures\//i.test(f)) || /seed.{0,10}data/i.test(docsBundle(ctx)),
|
|
1851
1852
|
impact: 'low', rating: 2, category: 'database',
|
|
1852
1853
|
fix: 'Add seed scripts and document local database setup.',
|
|
1853
1854
|
template: null, file: () => null, line: () => null,
|
|
1854
1855
|
},
|
|
1855
1856
|
ocAuthFlowDocumented: {
|
|
1856
1857
|
id: 'OC-T25', name: 'Authentication flow documented',
|
|
1857
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /auth.{0,15}flow|login.{0,15}flow|authenticate/i.test(docs); },
|
|
1858
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /auth.{0,15}flow|login.{0,15}flow|authenticate/i.test(docs); },
|
|
1858
1859
|
impact: 'high', rating: 4, category: 'authentication',
|
|
1859
1860
|
fix: 'Document authentication flow in AGENTS.md for OpenCode.',
|
|
1860
1861
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1861
1862
|
},
|
|
1862
1863
|
ocTokenHandlingGuidance: {
|
|
1863
1864
|
id: 'OC-T26', name: 'Token handling guidance documented',
|
|
1864
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /jwt|token.{0,15}refresh|access.{0,10}token|bearer/i.test(docs); },
|
|
1865
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /jwt|token.{0,15}refresh|access.{0,10}token|bearer/i.test(docs); },
|
|
1865
1866
|
impact: 'high', rating: 4, category: 'authentication',
|
|
1866
1867
|
fix: 'Document JWT/token patterns in AGENTS.md.',
|
|
1867
1868
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1868
1869
|
},
|
|
1869
1870
|
ocSessionManagementDocumented: {
|
|
1870
1871
|
id: 'OC-T27', name: 'Session management documented',
|
|
1871
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /session.{0,15}manag|cookie|next.?auth/i.test(docs); },
|
|
1872
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /session.{0,15}manag|cookie|next.?auth/i.test(docs); },
|
|
1872
1873
|
impact: 'medium', rating: 3, category: 'authentication',
|
|
1873
1874
|
fix: 'Document session management in AGENTS.md.',
|
|
1874
1875
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1875
1876
|
},
|
|
1876
1877
|
ocRbacPermissionsReferenced: {
|
|
1877
1878
|
id: 'OC-T28', name: 'RBAC / permissions model referenced',
|
|
1878
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rbac|role.?based|permission|authorization/i.test(docs); },
|
|
1879
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rbac|role.?based|permission|authorization/i.test(docs); },
|
|
1879
1880
|
impact: 'high', rating: 4, category: 'authentication',
|
|
1880
1881
|
fix: 'Document RBAC/permissions model in AGENTS.md.',
|
|
1881
1882
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1882
1883
|
},
|
|
1883
1884
|
ocOauthSsoMentioned: {
|
|
1884
1885
|
id: 'OC-T29', name: 'OAuth/SSO configuration documented',
|
|
1885
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /oauth|sso|saml|oidc/i.test(docs); },
|
|
1886
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /oauth|sso|saml|oidc/i.test(docs); },
|
|
1886
1887
|
impact: 'medium', rating: 3, category: 'authentication',
|
|
1887
1888
|
fix: 'Document OAuth/SSO provider in README.md.',
|
|
1888
1889
|
template: null, file: () => 'README.md', line: () => null,
|
|
1889
1890
|
},
|
|
1890
1891
|
ocCredentialRotationDocumented: {
|
|
1891
1892
|
id: 'OC-T30', name: 'Credential rotation policy documented',
|
|
1892
|
-
check: (ctx) => { const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rotat.{0,10}secret|rotat.{0,10}key|credential.{0,10}rotat/i.test(docs); },
|
|
1893
|
+
check: (ctx) => { if (!isAuthProject(ctx)) return null; const docs = docsBundle(ctx); if (!docs.trim()) return null; return /rotat.{0,10}secret|rotat.{0,10}key|credential.{0,10}rotat/i.test(docs); },
|
|
1893
1894
|
impact: 'medium', rating: 3, category: 'authentication',
|
|
1894
1895
|
fix: 'Document credential rotation in AGENTS.md.',
|
|
1895
1896
|
template: null, file: () => 'AGENTS.md', line: () => null,
|
|
1896
1897
|
},
|
|
1897
1898
|
ocLoggingConfigured: {
|
|
1898
1899
|
id: 'OC-T31', name: 'Logging framework configured',
|
|
1899
|
-
check: (ctx) => /winston|pino|bunyan|morgan|loguru/i.test(ctx.fileContent('package.json') || '') || ctx.files.some(f => /log(ger|ging)\.config/i.test(f)),
|
|
1900
|
+
check: (ctx) => !isMonitoringRelevant(ctx) ? null : /winston|pino|bunyan|morgan|loguru/i.test(ctx.fileContent('package.json') || '') || ctx.files.some(f => /log(ger|ging)\.config/i.test(f)),
|
|
1900
1901
|
impact: 'high', rating: 4, category: 'monitoring',
|
|
1901
1902
|
fix: 'Add structured logging and document log levels in AGENTS.md.',
|
|
1902
1903
|
template: null, file: () => 'package.json', line: () => null,
|
|
1903
1904
|
},
|
|
1904
1905
|
ocErrorTrackingSetup: {
|
|
1905
1906
|
id: 'OC-T32', name: 'Error tracking service configured',
|
|
1906
|
-
check: (ctx) => /sentry|bugsnag|rollbar/i.test(ctx.fileContent('package.json') || ''),
|
|
1907
|
+
check: (ctx) => !isMonitoringRelevant(ctx) ? null : /sentry|bugsnag|rollbar/i.test(ctx.fileContent('package.json') || ''),
|
|
1907
1908
|
impact: 'high', rating: 4, category: 'monitoring',
|
|
1908
1909
|
fix: 'Set up error tracking (Sentry) for production monitoring.',
|
|
1909
1910
|
template: null, file: () => null, line: () => null,
|
|
1910
1911
|
},
|
|
1911
1912
|
ocApmMetricsMentioned: {
|
|
1912
1913
|
id: 'OC-T33', name: 'APM / metrics platform documented',
|
|
1913
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /datadog|newrelic|prometheus|grafana|opentelemetry|apm/i.test(docs); },
|
|
1914
|
+
check: (ctx) => { if (!isMonitoringRelevant(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /datadog|newrelic|prometheus|grafana|opentelemetry|apm/i.test(docs); },
|
|
1914
1915
|
impact: 'medium', rating: 3, category: 'monitoring',
|
|
1915
1916
|
fix: 'Document APM platform in README.md.',
|
|
1916
1917
|
template: null, file: () => 'README.md', line: () => null,
|
|
1917
1918
|
},
|
|
1918
1919
|
ocHealthCheckEndpoint: {
|
|
1919
1920
|
id: 'OC-T34', name: 'Health check endpoint documented',
|
|
1920
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /health.?check|\/health|\/ping|\/status/i.test(docs); },
|
|
1921
|
+
check: (ctx) => { if (!isMonitoringRelevant(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /health.?check|\/health|\/ping|\/status/i.test(docs); },
|
|
1921
1922
|
impact: 'medium', rating: 3, category: 'monitoring',
|
|
1922
1923
|
fix: 'Document health check endpoint in README.md.',
|
|
1923
1924
|
template: null, file: () => 'README.md', line: () => null,
|
|
1924
1925
|
},
|
|
1925
1926
|
ocAlertingReferenced: {
|
|
1926
1927
|
id: 'OC-T35', name: 'Alerting strategy referenced',
|
|
1927
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /alert|pagerduty|opsgenie|oncall|incident/i.test(docs); },
|
|
1928
|
+
check: (ctx) => { if (!isMonitoringRelevant(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /alert|pagerduty|opsgenie|oncall|incident/i.test(docs); },
|
|
1928
1929
|
impact: 'medium', rating: 3, category: 'monitoring',
|
|
1929
1930
|
fix: 'Document alerting strategy in README.md.',
|
|
1930
1931
|
template: null, file: () => 'README.md', line: () => null,
|
|
1931
1932
|
},
|
|
1932
1933
|
ocLogRotationMentioned: {
|
|
1933
1934
|
id: 'OC-T36', name: 'Log rotation / retention documented',
|
|
1934
|
-
check: (ctx) => { const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /log.{0,15}rotat|log.{0,15}retent/i.test(docs); },
|
|
1935
|
+
check: (ctx) => { if (!isMonitoringRelevant(ctx)) return null; const docs = docsBundle(ctx) + (ctx.fileContent('README.md') || ''); if (!docs.trim()) return null; return /log.{0,15}rotat|log.{0,15}retent/i.test(docs); },
|
|
1935
1936
|
impact: 'low', rating: 2, category: 'monitoring',
|
|
1936
1937
|
fix: 'Document log rotation policy in README.md.',
|
|
1937
1938
|
template: null, file: () => 'README.md', line: () => null,
|