@nerviq/cli 0.0.1 → 0.9.0-beta.1

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 (148) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/LICENSE +21 -0
  3. package/README.md +447 -0
  4. package/bin/cli.js +749 -0
  5. package/content/case-study-template.md +91 -0
  6. package/content/claims-governance.md +37 -0
  7. package/content/claude-code/audit-repo/SKILL.md +20 -0
  8. package/content/claude-native-integration.md +60 -0
  9. package/content/devto-article.json +9 -0
  10. package/content/launch-posts.md +226 -0
  11. package/content/pilot-rollout-kit.md +30 -0
  12. package/content/release-checklist.md +31 -0
  13. package/package.json +53 -4
  14. package/src/activity.js +529 -0
  15. package/src/aider/activity.js +226 -0
  16. package/src/aider/config-parser.js +166 -0
  17. package/src/aider/context.js +158 -0
  18. package/src/aider/deep-review.js +316 -0
  19. package/src/aider/domain-packs.js +278 -0
  20. package/src/aider/freshness.js +168 -0
  21. package/src/aider/governance.js +253 -0
  22. package/src/aider/interactive.js +334 -0
  23. package/src/aider/mcp-packs.js +98 -0
  24. package/src/aider/patch.js +214 -0
  25. package/src/aider/plans.js +186 -0
  26. package/src/aider/premium.js +360 -0
  27. package/src/aider/setup.js +404 -0
  28. package/src/aider/techniques.js +1323 -0
  29. package/src/analyze.js +821 -0
  30. package/src/audit.js +1003 -0
  31. package/src/badge.js +13 -0
  32. package/src/benchmark.js +339 -0
  33. package/src/claudex-sync.json +7 -0
  34. package/src/codex/activity.js +324 -0
  35. package/src/codex/config-parser.js +183 -0
  36. package/src/codex/context.js +221 -0
  37. package/src/codex/deep-review.js +493 -0
  38. package/src/codex/domain-packs.js +372 -0
  39. package/src/codex/freshness.js +167 -0
  40. package/src/codex/governance.js +192 -0
  41. package/src/codex/interactive.js +618 -0
  42. package/src/codex/mcp-packs.js +660 -0
  43. package/src/codex/patch.js +209 -0
  44. package/src/codex/plans.js +251 -0
  45. package/src/codex/premium.js +614 -0
  46. package/src/codex/setup.js +603 -0
  47. package/src/codex/techniques.js +2649 -0
  48. package/src/context.js +272 -0
  49. package/src/copilot/activity.js +309 -0
  50. package/src/copilot/config-parser.js +226 -0
  51. package/src/copilot/context.js +197 -0
  52. package/src/copilot/deep-review.js +346 -0
  53. package/src/copilot/domain-packs.js +350 -0
  54. package/src/copilot/freshness.js +197 -0
  55. package/src/copilot/governance.js +222 -0
  56. package/src/copilot/interactive.js +406 -0
  57. package/src/copilot/mcp-packs.js +572 -0
  58. package/src/copilot/patch.js +238 -0
  59. package/src/copilot/plans.js +253 -0
  60. package/src/copilot/premium.js +450 -0
  61. package/src/copilot/setup.js +488 -0
  62. package/src/copilot/techniques.js +1822 -0
  63. package/src/cursor/activity.js +301 -0
  64. package/src/cursor/config-parser.js +265 -0
  65. package/src/cursor/context.js +236 -0
  66. package/src/cursor/deep-review.js +334 -0
  67. package/src/cursor/domain-packs.js +346 -0
  68. package/src/cursor/freshness.js +214 -0
  69. package/src/cursor/governance.js +229 -0
  70. package/src/cursor/interactive.js +391 -0
  71. package/src/cursor/mcp-packs.js +571 -0
  72. package/src/cursor/patch.js +243 -0
  73. package/src/cursor/plans.js +254 -0
  74. package/src/cursor/premium.js +468 -0
  75. package/src/cursor/setup.js +488 -0
  76. package/src/cursor/techniques.js +1786 -0
  77. package/src/deep-review.js +345 -0
  78. package/src/domain-packs.js +364 -0
  79. package/src/formatters/sarif.js +115 -0
  80. package/src/gemini/activity.js +402 -0
  81. package/src/gemini/config-parser.js +275 -0
  82. package/src/gemini/context.js +221 -0
  83. package/src/gemini/deep-review.js +559 -0
  84. package/src/gemini/domain-packs.js +371 -0
  85. package/src/gemini/freshness.js +204 -0
  86. package/src/gemini/governance.js +201 -0
  87. package/src/gemini/interactive.js +860 -0
  88. package/src/gemini/mcp-packs.js +658 -0
  89. package/src/gemini/patch.js +229 -0
  90. package/src/gemini/plans.js +269 -0
  91. package/src/gemini/premium.js +759 -0
  92. package/src/gemini/setup.js +692 -0
  93. package/src/gemini/techniques.js +2084 -0
  94. package/src/governance.js +523 -0
  95. package/src/harmony/advisor.js +383 -0
  96. package/src/harmony/audit.js +303 -0
  97. package/src/harmony/canon.js +444 -0
  98. package/src/harmony/cli.js +331 -0
  99. package/src/harmony/drift.js +401 -0
  100. package/src/harmony/governance.js +313 -0
  101. package/src/harmony/memory.js +238 -0
  102. package/src/harmony/sync.js +458 -0
  103. package/src/harmony/watch.js +336 -0
  104. package/src/index.js +256 -0
  105. package/src/insights.js +119 -0
  106. package/src/interactive.js +118 -0
  107. package/src/mcp-packs.js +597 -0
  108. package/src/opencode/activity.js +286 -0
  109. package/src/opencode/config-parser.js +109 -0
  110. package/src/opencode/context.js +247 -0
  111. package/src/opencode/deep-review.js +313 -0
  112. package/src/opencode/domain-packs.js +240 -0
  113. package/src/opencode/freshness.js +158 -0
  114. package/src/opencode/governance.js +159 -0
  115. package/src/opencode/interactive.js +392 -0
  116. package/src/opencode/mcp-packs.js +474 -0
  117. package/src/opencode/patch.js +184 -0
  118. package/src/opencode/plans.js +231 -0
  119. package/src/opencode/premium.js +413 -0
  120. package/src/opencode/setup.js +449 -0
  121. package/src/opencode/techniques.js +1713 -0
  122. package/src/plans.js +655 -0
  123. package/src/secret-patterns.js +30 -0
  124. package/src/setup.js +1274 -0
  125. package/src/synergy/adaptive.js +261 -0
  126. package/src/synergy/compensation.js +156 -0
  127. package/src/synergy/evidence.js +193 -0
  128. package/src/synergy/learning.js +184 -0
  129. package/src/synergy/patterns.js +227 -0
  130. package/src/synergy/ranking.js +83 -0
  131. package/src/synergy/report.js +163 -0
  132. package/src/synergy/routing.js +152 -0
  133. package/src/techniques.js +1354 -0
  134. package/src/watch.js +229 -0
  135. package/src/windsurf/activity.js +302 -0
  136. package/src/windsurf/config-parser.js +267 -0
  137. package/src/windsurf/context.js +249 -0
  138. package/src/windsurf/deep-review.js +337 -0
  139. package/src/windsurf/domain-packs.js +348 -0
  140. package/src/windsurf/freshness.js +215 -0
  141. package/src/windsurf/governance.js +231 -0
  142. package/src/windsurf/interactive.js +388 -0
  143. package/src/windsurf/mcp-packs.js +535 -0
  144. package/src/windsurf/patch.js +231 -0
  145. package/src/windsurf/plans.js +247 -0
  146. package/src/windsurf/premium.js +467 -0
  147. package/src/windsurf/setup.js +471 -0
  148. package/src/windsurf/techniques.js +1758 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Gemini CLI project context.
3
+ *
4
+ * Extends the shared ProjectContext with Gemini-specific file lookups,
5
+ * settings.json parsing (JSON), and command/policy TOML parsing.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+ const path = require('path');
11
+ const { spawnSync } = require('child_process');
12
+ const { ProjectContext } = require('../context');
13
+ const { tryParseJson, tryParseToml, getValueByPath } = require('./config-parser');
14
+
15
+ let geminiVersionCache = null;
16
+
17
+ function detectGeminiVersion() {
18
+ if (geminiVersionCache !== null) {
19
+ return geminiVersionCache;
20
+ }
21
+
22
+ try {
23
+ const result = spawnSync('gemini', ['--version'], { encoding: 'utf8' });
24
+ const output = `${result.stdout || ''} ${result.stderr || ''}`.trim();
25
+ const match = output.match(/gemini(?:-cli)?\s+([^\s]+)/i);
26
+ geminiVersionCache = match ? match[1] : (output || null);
27
+ return geminiVersionCache;
28
+ } catch {
29
+ geminiVersionCache = null;
30
+ return null;
31
+ }
32
+ }
33
+
34
+ function listDirs(fullPath) {
35
+ try {
36
+ return fs.readdirSync(fullPath, { withFileTypes: true }).filter(entry => entry.isDirectory());
37
+ } catch {
38
+ return [];
39
+ }
40
+ }
41
+
42
+ function listFiles(fullPath, filter) {
43
+ try {
44
+ const entries = fs.readdirSync(fullPath).filter(f => !f.startsWith('.'));
45
+ return filter ? entries.filter(filter) : entries;
46
+ } catch {
47
+ return [];
48
+ }
49
+ }
50
+
51
+ class GeminiProjectContext extends ProjectContext {
52
+
53
+ // ─── GEMINI.md content ───────────────────────────────────────────────
54
+
55
+ geminiMdContent() {
56
+ const direct = this.fileContent('GEMINI.md');
57
+ if (direct) return direct;
58
+
59
+ // Fallback: use context.fileName from settings if configured
60
+ const contextFileName = this.configValue('context.fileName');
61
+ if (contextFileName) {
62
+ const content = this.fileContent(contextFileName);
63
+ if (content) return content;
64
+ }
65
+
66
+ return null;
67
+ }
68
+
69
+ globalGeminiMdContent() {
70
+ const homeDir = os.homedir();
71
+ const globalPath = path.join(homeDir, '.gemini', 'GEMINI.md');
72
+ try {
73
+ return fs.readFileSync(globalPath, 'utf8');
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+
79
+ componentGeminiMd(dirPath) {
80
+ const fullPath = path.join(this.dir, dirPath, 'GEMINI.md');
81
+ try {
82
+ return fs.readFileSync(fullPath, 'utf8');
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+
88
+ // ─── settings.json parsing ───────────────────────────────────────────
89
+
90
+ settingsJson() {
91
+ const content = this.fileContent('.gemini/settings.json');
92
+ if (!content) {
93
+ return { ok: false, data: null, error: 'missing project settings', source: '.gemini/settings.json' };
94
+ }
95
+ const parsed = tryParseJson(content);
96
+ return { ...parsed, source: '.gemini/settings.json' };
97
+ }
98
+
99
+ globalSettingsJson() {
100
+ const homeDir = os.homedir();
101
+ const globalPath = path.join(homeDir, '.gemini', 'settings.json');
102
+ try {
103
+ const content = fs.readFileSync(globalPath, 'utf8');
104
+ const parsed = tryParseJson(content);
105
+ return { ...parsed, source: globalPath };
106
+ } catch {
107
+ return { ok: false, data: null, error: 'missing global settings', source: globalPath };
108
+ }
109
+ }
110
+
111
+ // ─── Config value with precedence (project > global) ─────────────────
112
+
113
+ configValue(key) {
114
+ const project = this.settingsJson();
115
+ if (project.ok) {
116
+ const projectValue = getValueByPath(project.data, key);
117
+ if (projectValue !== undefined) return projectValue;
118
+ }
119
+
120
+ const globalSettings = this.globalSettingsJson();
121
+ if (globalSettings.ok) {
122
+ return getValueByPath(globalSettings.data, key);
123
+ }
124
+
125
+ return undefined;
126
+ }
127
+
128
+ // ─── Hooks ────────────────────────────────────────────────────────────
129
+
130
+ hooksConfig() {
131
+ const hooks = this.configValue('hooks');
132
+ if (!hooks || typeof hooks !== 'object') return null;
133
+ return hooks;
134
+ }
135
+
136
+ // ─── MCP servers ──────────────────────────────────────────────────────
137
+
138
+ mcpServers() {
139
+ return this.configValue('mcpServers') || {};
140
+ }
141
+
142
+ // ─── Command files (.gemini/commands/*.toml) ──────────────────────────
143
+
144
+ commandFiles() {
145
+ const commandsDir = path.join(this.dir, '.gemini', 'commands');
146
+ return listFiles(commandsDir, f => f.endsWith('.toml'))
147
+ .map(f => path.join('.gemini', 'commands', f).replace(/\\/g, '/'));
148
+ }
149
+
150
+ commandConfig(fileName) {
151
+ const content = this.fileContent(fileName);
152
+ if (!content) return { ok: false, data: null, error: 'missing command file' };
153
+ return tryParseToml(content);
154
+ }
155
+
156
+ // ─── Agent files (.gemini/agents/*.md) ────────────────────────────────
157
+
158
+ agentFiles() {
159
+ const agentsDir = path.join(this.dir, '.gemini', 'agents');
160
+ return listFiles(agentsDir, f => f.endsWith('.md'))
161
+ .map(f => path.join('.gemini', 'agents', f).replace(/\\/g, '/'));
162
+ }
163
+
164
+ // ─── Skill directories (.gemini/skills/*) ─────────────────────────────
165
+
166
+ skillDirs() {
167
+ const skillsDir = path.join(this.dir, '.gemini', 'skills');
168
+ return listDirs(skillsDir).map(entry => entry.name);
169
+ }
170
+
171
+ // ─── Extension directories ────────────────────────────────────────────
172
+
173
+ extensionDirs() {
174
+ const extDir = path.join(this.dir, '.gemini', 'extensions');
175
+ return listDirs(extDir).map(entry => entry.name);
176
+ }
177
+
178
+ // ─── Policy files (.gemini/policy/*.toml or .gemini/policies/*.toml) ──
179
+
180
+ policyFiles() {
181
+ const candidates = ['.gemini/policy', '.gemini/policies'];
182
+ const files = [];
183
+
184
+ for (const dirPath of candidates) {
185
+ const fullPath = path.join(this.dir, dirPath);
186
+ for (const f of listFiles(fullPath, fn => fn.endsWith('.toml'))) {
187
+ files.push(path.join(dirPath, f).replace(/\\/g, '/'));
188
+ }
189
+ }
190
+
191
+ return files;
192
+ }
193
+
194
+ policyConfig(fileName) {
195
+ const content = this.fileContent(fileName);
196
+ if (!content) return { ok: false, data: null, error: 'missing policy file' };
197
+ return tryParseToml(content);
198
+ }
199
+
200
+ // ─── Static detection ─────────────────────────────────────────────────
201
+
202
+ static isGeminiRepo(dir) {
203
+ try {
204
+ return fs.existsSync(path.join(dir, 'GEMINI.md')) ||
205
+ fs.existsSync(path.join(dir, '.gemini'));
206
+ } catch {
207
+ return false;
208
+ }
209
+ }
210
+
211
+ // ─── Stack detection (reuse shared) ───────────────────────────────────
212
+
213
+ detectStacks(STACKS) {
214
+ return super.detectStacks(STACKS);
215
+ }
216
+ }
217
+
218
+ module.exports = {
219
+ GeminiProjectContext,
220
+ detectGeminiVersion,
221
+ };