pgserve 2.1.2 → 2.2.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 (227) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +105 -1
  3. package/bin/autopg-wrapper.cjs +16 -0
  4. package/bin/pgserve-wrapper.cjs +31 -6
  5. package/bin/postgres-server.js +80 -7
  6. package/console/README.md +131 -0
  7. package/console/api.js +173 -0
  8. package/console/app.jsx +483 -0
  9. package/console/colors_and_type.css +227 -0
  10. package/console/components.jsx +167 -0
  11. package/console/console.css +1666 -0
  12. package/console/data.jsx +350 -0
  13. package/console/index.html +31 -0
  14. package/console/screens/databases.jsx +5 -0
  15. package/console/screens/health.jsx +5 -0
  16. package/console/screens/ingress.jsx +5 -0
  17. package/console/screens/optimizer.jsx +5 -0
  18. package/console/screens/rlm-sim.jsx +5 -0
  19. package/console/screens/rlm-trace.jsx +5 -0
  20. package/console/screens/security.jsx +5 -0
  21. package/console/screens/settings.jsx +611 -0
  22. package/console/screens/sql.jsx +5 -0
  23. package/console/screens/sync.jsx +5 -0
  24. package/console/screens/tables.jsx +5 -0
  25. package/console/tweaks-panel.jsx +425 -0
  26. package/package.json +11 -1
  27. package/src/cli-config.cjs +310 -0
  28. package/src/cli-install.cjs +98 -11
  29. package/src/cli-restart.cjs +228 -0
  30. package/src/cli-ui.cjs +580 -0
  31. package/src/cluster.js +43 -38
  32. package/src/postgres.js +141 -19
  33. package/src/settings-loader.cjs +235 -0
  34. package/src/settings-migrate.cjs +212 -0
  35. package/src/settings-pg-args.cjs +146 -0
  36. package/src/settings-schema.cjs +422 -0
  37. package/src/settings-validator.cjs +416 -0
  38. package/src/settings-writer.cjs +288 -0
  39. package/.claude/context/windows-debug.md +0 -119
  40. package/.genie/AGENTS.md +0 -15
  41. package/.genie/agents/README.md +0 -110
  42. package/.genie/agents/analyze.md +0 -176
  43. package/.genie/agents/forge.md +0 -290
  44. package/.genie/agents/garbage-cleaner.md +0 -324
  45. package/.genie/agents/garbage-collector.md +0 -596
  46. package/.genie/agents/github-issue-gc.md +0 -618
  47. package/.genie/agents/review.md +0 -380
  48. package/.genie/agents/semantic-analyzer/find-duplicates.md +0 -90
  49. package/.genie/agents/semantic-analyzer/find-orphans.md +0 -99
  50. package/.genie/agents/semantic-analyzer.md +0 -101
  51. package/.genie/agents/update.md +0 -182
  52. package/.genie/agents/wish.md +0 -357
  53. package/.genie/brainstorms/pgserve-v2/DESIGN.md +0 -174
  54. package/.genie/code/AGENTS.md +0 -694
  55. package/.genie/code/agents/audit/risk.md +0 -173
  56. package/.genie/code/agents/audit/security.md +0 -189
  57. package/.genie/code/agents/audit.md +0 -145
  58. package/.genie/code/agents/challenge.md +0 -230
  59. package/.genie/code/agents/change-reviewer.md +0 -295
  60. package/.genie/code/agents/code-garbage-collector.md +0 -425
  61. package/.genie/code/agents/code-quality.md +0 -410
  62. package/.genie/code/agents/commit-suggester.md +0 -255
  63. package/.genie/code/agents/commit.md +0 -124
  64. package/.genie/code/agents/consensus.md +0 -204
  65. package/.genie/code/agents/daily-standup.md +0 -722
  66. package/.genie/code/agents/docgen.md +0 -48
  67. package/.genie/code/agents/explore.md +0 -79
  68. package/.genie/code/agents/fix.md +0 -100
  69. package/.genie/code/agents/git/commit-advisory.md +0 -219
  70. package/.genie/code/agents/git/workflows/issue.md +0 -244
  71. package/.genie/code/agents/git/workflows/pr.md +0 -179
  72. package/.genie/code/agents/git/workflows/release.md +0 -460
  73. package/.genie/code/agents/git/workflows/report.md +0 -342
  74. package/.genie/code/agents/git.md +0 -432
  75. package/.genie/code/agents/implementor.md +0 -161
  76. package/.genie/code/agents/install.md +0 -515
  77. package/.genie/code/agents/issue-creator.md +0 -344
  78. package/.genie/code/agents/polish.md +0 -116
  79. package/.genie/code/agents/qa.md +0 -653
  80. package/.genie/code/agents/refactor.md +0 -294
  81. package/.genie/code/agents/release.md +0 -1129
  82. package/.genie/code/agents/roadmap.md +0 -885
  83. package/.genie/code/agents/tests.md +0 -557
  84. package/.genie/code/agents/tracer.md +0 -50
  85. package/.genie/code/agents/update/upstream-update.md +0 -85
  86. package/.genie/code/agents/update/versions/generic-update.md +0 -305
  87. package/.genie/code/agents/vibe.md +0 -1317
  88. package/.genie/code/spells/agent-configuration.md +0 -58
  89. package/.genie/code/spells/automated-rc-publishing.md +0 -106
  90. package/.genie/code/spells/branch-tracker-guidance.md +0 -28
  91. package/.genie/code/spells/debug.md +0 -320
  92. package/.genie/code/spells/emoji-naming-convention.md +0 -303
  93. package/.genie/code/spells/evidence-storage.md +0 -26
  94. package/.genie/code/spells/file-naming-rules.md +0 -35
  95. package/.genie/code/spells/forge-code-blueprints.md +0 -195
  96. package/.genie/code/spells/genie-integration.md +0 -153
  97. package/.genie/code/spells/publishing-protocol.md +0 -61
  98. package/.genie/code/spells/team-consultation-protocol.md +0 -284
  99. package/.genie/code/spells/tool-requirements.md +0 -20
  100. package/.genie/code/spells/triad-maintenance-protocol.md +0 -154
  101. package/.genie/code/teams/tech-council/council.md +0 -328
  102. package/.genie/code/teams/tech-council/jt.md +0 -352
  103. package/.genie/code/teams/tech-council/nayr.md +0 -305
  104. package/.genie/code/teams/tech-council/oettam.md +0 -375
  105. package/.genie/neurons/README.md +0 -193
  106. package/.genie/neurons/forge.md +0 -106
  107. package/.genie/neurons/genie.md +0 -63
  108. package/.genie/neurons/review.md +0 -106
  109. package/.genie/neurons/wish.md +0 -104
  110. package/.genie/product/README.md +0 -20
  111. package/.genie/product/cli-automation.md +0 -359
  112. package/.genie/product/environment.md +0 -60
  113. package/.genie/product/mission.md +0 -60
  114. package/.genie/product/roadmap.md +0 -44
  115. package/.genie/product/tech-stack.md +0 -34
  116. package/.genie/product/templates/context-template.md +0 -218
  117. package/.genie/product/templates/qa-done-report-template.md +0 -68
  118. package/.genie/product/templates/review-report-template.md +0 -89
  119. package/.genie/product/templates/wish-template.md +0 -120
  120. package/.genie/scripts/helpers/analyze-commit.js +0 -195
  121. package/.genie/scripts/helpers/bullet-counter.js +0 -194
  122. package/.genie/scripts/helpers/bullet-find.js +0 -289
  123. package/.genie/scripts/helpers/bullet-id.js +0 -244
  124. package/.genie/scripts/helpers/check-secrets.js +0 -237
  125. package/.genie/scripts/helpers/count-tokens.js +0 -200
  126. package/.genie/scripts/helpers/create-frontmatter.js +0 -456
  127. package/.genie/scripts/helpers/detect-markers.js +0 -293
  128. package/.genie/scripts/helpers/detect-todos.js +0 -267
  129. package/.genie/scripts/helpers/detect-unlabeled-blocks.js +0 -135
  130. package/.genie/scripts/helpers/embeddings.js +0 -344
  131. package/.genie/scripts/helpers/find-empty-sections.js +0 -158
  132. package/.genie/scripts/helpers/index.js +0 -319
  133. package/.genie/scripts/helpers/validate-frontmatter.js +0 -578
  134. package/.genie/scripts/helpers/validate-links.js +0 -207
  135. package/.genie/scripts/helpers/validate-paths.js +0 -373
  136. package/.genie/spells/README.md +0 -9
  137. package/.genie/spells/ace-protocol.md +0 -118
  138. package/.genie/spells/ask-one-at-a-time.md +0 -175
  139. package/.genie/spells/backup-analyzer.md +0 -542
  140. package/.genie/spells/blocker.md +0 -12
  141. package/.genie/spells/break-things-move-fast.md +0 -56
  142. package/.genie/spells/context-candidates.md +0 -72
  143. package/.genie/spells/context-critic.md +0 -51
  144. package/.genie/spells/defer-to-expertise.md +0 -278
  145. package/.genie/spells/delegate-dont-do.md +0 -292
  146. package/.genie/spells/error-investigation-protocol.md +0 -328
  147. package/.genie/spells/evidence-based-completion.md +0 -273
  148. package/.genie/spells/experiment.md +0 -65
  149. package/.genie/spells/file-creation-protocol.md +0 -229
  150. package/.genie/spells/forge-integration.md +0 -281
  151. package/.genie/spells/forge-orchestration.md +0 -514
  152. package/.genie/spells/gather-context.md +0 -18
  153. package/.genie/spells/global-health-check.md +0 -34
  154. package/.genie/spells/global-noop-roundtrip.md +0 -25
  155. package/.genie/spells/install-genie.md +0 -1232
  156. package/.genie/spells/install.md +0 -82
  157. package/.genie/spells/investigate-before-commit.md +0 -112
  158. package/.genie/spells/know-yourself.md +0 -288
  159. package/.genie/spells/learn.md +0 -828
  160. package/.genie/spells/mcp-diagnostic-protocol.md +0 -246
  161. package/.genie/spells/mcp-first.md +0 -124
  162. package/.genie/spells/multi-step-execution.md +0 -67
  163. package/.genie/spells/orchestration-boundary-protocol.md +0 -256
  164. package/.genie/spells/orchestrator-not-implementor.md +0 -189
  165. package/.genie/spells/prompt.md +0 -746
  166. package/.genie/spells/reflect.md +0 -404
  167. package/.genie/spells/routing-decision-matrix.md +0 -368
  168. package/.genie/spells/run-in-parallel.md +0 -12
  169. package/.genie/spells/session-state-updater-example.md +0 -196
  170. package/.genie/spells/session-state-updater.md +0 -220
  171. package/.genie/spells/track-long-running-tasks.md +0 -133
  172. package/.genie/spells/troubleshoot-infrastructure.md +0 -176
  173. package/.genie/spells/upgrade-genie.md +0 -415
  174. package/.genie/spells/url-presentation-protocol.md +0 -301
  175. package/.genie/spells/wish-initiation.md +0 -158
  176. package/.genie/spells/wish-issue-linkage.md +0 -410
  177. package/.genie/spells/wish-lifecycle.md +0 -100
  178. package/.genie/state/provider-status.json +0 -3
  179. package/.genie/state/version.json +0 -16
  180. package/.genie/wishes/canonical-pgserve-pm2-supervision/WISH.md +0 -290
  181. package/.genie/wishes/pgserve-v2/BRIEF-from-genie-pgserve.md +0 -99
  182. package/.genie/wishes/pgserve-v2/WISH.md +0 -442
  183. package/.genie/wishes/release-system-genie-pattern/WISH.md +0 -268
  184. package/.genie/wishes/release-system-genie-pattern/validation.md +0 -205
  185. package/.gitguardian.yaml +0 -29
  186. package/.gitguardianignore +0 -16
  187. package/.github/workflows/ci.yml +0 -122
  188. package/.github/workflows/release.yml +0 -289
  189. package/.github/workflows/version.yml +0 -228
  190. package/.husky/pre-commit +0 -2
  191. package/AGENTS.md +0 -433
  192. package/CLAUDE.md +0 -1
  193. package/Makefile +0 -285
  194. package/assets/icon.ico +0 -0
  195. package/bun.lock +0 -435
  196. package/bunfig.toml +0 -28
  197. package/ecosystem.config.cjs +0 -23
  198. package/eslint.config.js +0 -63
  199. package/examples/multi-tenant-demo.js +0 -104
  200. package/install.sh +0 -123
  201. package/knip.json +0 -9
  202. package/scripts/test-bun-self-heal.sh +0 -163
  203. package/scripts/test-npx.sh +0 -60
  204. package/tests/audit.test.js +0 -189
  205. package/tests/backpressure.test.js +0 -167
  206. package/tests/benchmarks/runner.js +0 -1197
  207. package/tests/benchmarks/vector-generator.js +0 -368
  208. package/tests/cli-install.test.js +0 -322
  209. package/tests/control-db.test.js +0 -285
  210. package/tests/daemon-control.test.js +0 -171
  211. package/tests/daemon-fingerprint-integration.test.js +0 -111
  212. package/tests/daemon-pr24-regression.test.js +0 -198
  213. package/tests/fingerprint.test.js +0 -263
  214. package/tests/fixtures/240-orphan-seed.sql +0 -30
  215. package/tests/multi-tenant.test.js +0 -374
  216. package/tests/orphan-cleanup.test.js +0 -390
  217. package/tests/pg-version-regex.test.js +0 -129
  218. package/tests/quick-bench.js +0 -135
  219. package/tests/router-handshake-retry.test.js +0 -119
  220. package/tests/router-handshake-watchdog.test.js +0 -110
  221. package/tests/sdk.test.js +0 -71
  222. package/tests/stale-postmaster-pid.test.js +0 -85
  223. package/tests/stress-test.js +0 -439
  224. package/tests/sync-perf-test.js +0 -150
  225. package/tests/tcp-listen.test.js +0 -368
  226. package/tests/tenancy.test.js +0 -403
  227. package/tests/wrapper-supervision.test.js +0 -107
@@ -1,344 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Embeddings Helper - Learning Deduplication
5
- *
6
- * Checks if new learning already exists in target section.
7
- * Uses transformers.js with all-MiniLM-L6-v2 (85MB, CPU-only).
8
- *
9
- * Usage:
10
- * genie helper embeddings "new learning text" file.md "Section Name"
11
- *
12
- * Output: Top matches with similarity scores and recommendations
13
- * 0.85+ = DUPLICATE (merge or skip)
14
- * 0.70-0.85 = RELATED (evaluate carefully)
15
- * <0.70 = DIFFERENT (safe to append)
16
- */
17
-
18
- const fs = require('fs');
19
- const path = require('path');
20
- const crypto = require('crypto');
21
-
22
- // Lazy load transformers (only when needed)
23
- let pipeline = null;
24
- let embedder = null;
25
-
26
- async function initEmbedder() {
27
- if (!embedder) {
28
- const { pipeline: pipelineImport } = await import('@xenova/transformers');
29
- pipeline = pipelineImport;
30
-
31
- // Use all-MiniLM-L6-v2 for sentence embeddings
32
- // Show progress indicator on first download (85MB model)
33
- console.error('⏳ Loading embedding model (first time: downloads 85MB)...');
34
- embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', {
35
- progress_callback: (progress) => {
36
- if (progress.status === 'downloading' && progress.progress !== undefined) {
37
- const percent = Math.round(progress.progress);
38
- if (percent % 10 === 0) { // Log every 10%
39
- console.error(` Downloading: ${percent}%`);
40
- }
41
- }
42
- }
43
- });
44
- console.error('✅ Model loaded!\n');
45
- }
46
- return embedder;
47
- }
48
-
49
- /**
50
- * Compute cosine similarity between two vectors
51
- */
52
- function cosineSimilarity(vecA, vecB) {
53
- let dotProduct = 0;
54
- let normA = 0;
55
- let normB = 0;
56
-
57
- for (let i = 0; i < vecA.length; i++) {
58
- dotProduct += vecA[i] * vecB[i];
59
- normA += vecA[i] * vecA[i];
60
- normB += vecB[i] * vecB[i];
61
- }
62
-
63
- return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
64
- }
65
-
66
- /**
67
- * Get embedding for text
68
- */
69
- async function getEmbedding(text) {
70
- const model = await initEmbedder();
71
- const output = await model(text, { pooling: 'mean', normalize: true });
72
- return Array.from(output.data);
73
- }
74
-
75
- /**
76
- * Validate that file path is within workspace (security)
77
- */
78
- function validateFilePath(filePath) {
79
- const absPath = path.resolve(filePath);
80
- const workspaceRoot = path.resolve(process.cwd());
81
-
82
- if (!absPath.startsWith(workspaceRoot)) {
83
- throw new Error(`Security: Path outside workspace not allowed: ${filePath}`);
84
- }
85
-
86
- return absPath;
87
- }
88
-
89
- /**
90
- * Extract section content from markdown file
91
- * @param {string} fileContent - File content (already read)
92
- * @param {string} sectionName - Section header to extract
93
- */
94
- function extractSection(fileContent, sectionName) {
95
- const lines = fileContent.split('\n');
96
-
97
- const sectionLines = [];
98
- let inSection = false;
99
- let sectionLevel = 0;
100
-
101
- for (let i = 0; i < lines.length; i++) {
102
- const line = lines[i];
103
- const headerMatch = line.match(/^(#{1,6})\s+(.+)$/); // Added $ anchor
104
-
105
- if (headerMatch) {
106
- const level = headerMatch[1].length;
107
- const title = headerMatch[2].trim();
108
-
109
- if (title.includes(sectionName) || title === sectionName) {
110
- inSection = true;
111
- sectionLevel = level;
112
- continue;
113
- } else if (inSection && level <= sectionLevel) {
114
- // Hit next section at same/higher level, stop
115
- break;
116
- }
117
- }
118
-
119
- if (inSection && line.trim()) {
120
- // Skip code blocks and markdown formatting
121
- if (!line.startsWith('```') && !line.startsWith('---')) {
122
- sectionLines.push({ text: line.trim(), line: i + 1 });
123
- }
124
- }
125
- }
126
-
127
- return sectionLines;
128
- }
129
-
130
- /**
131
- * Get cache path for file + section
132
- */
133
- function getCachePath(filePath, sectionName) {
134
- const hash = crypto.createHash('md5')
135
- .update(filePath + ':' + sectionName)
136
- .digest('hex');
137
-
138
- const cacheDir = path.join(process.cwd(), '.genie', '.cache', 'embeddings');
139
- if (!fs.existsSync(cacheDir)) {
140
- fs.mkdirSync(cacheDir, { recursive: true });
141
- }
142
-
143
- return path.join(cacheDir, `${hash}.json`);
144
- }
145
-
146
- /**
147
- * Get recommendation based on similarity score
148
- */
149
- function getRecommendation(similarity) {
150
- if (similarity >= 0.85) return 'DUPLICATE';
151
- if (similarity >= 0.70) return 'RELATED';
152
- return 'DIFFERENT';
153
- }
154
-
155
- /**
156
- * Compare new learning to section (with caching)
157
- */
158
- async function compareToSection(newText, filePath, sectionName) {
159
- // Security: Validate file path is within workspace
160
- const validatedPath = validateFilePath(filePath);
161
-
162
- // Read file once (optimization: avoid dual reads)
163
- const fileContent = fs.readFileSync(validatedPath, 'utf-8');
164
-
165
- // Stage 1: Check for exact match with grep (fast)
166
- if (fileContent.includes(newText)) {
167
- return {
168
- stage: 1,
169
- exact_match: true,
170
- recommendation: 'DUPLICATE (exact match via grep)'
171
- };
172
- }
173
-
174
- // Stage 2: Semantic comparison (thorough)
175
- const cachePath = getCachePath(validatedPath, sectionName);
176
- let cached = null;
177
-
178
- // Try to load cache
179
- if (fs.existsSync(cachePath)) {
180
- try {
181
- cached = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
182
- } catch (err) {
183
- // Cache invalid, will rebuild
184
- }
185
- }
186
-
187
- // Extract section lines (pass content to avoid re-reading file)
188
- const sectionLines = extractSection(fileContent, sectionName);
189
-
190
- if (sectionLines.length === 0) {
191
- return {
192
- error: `Section "${sectionName}" not found in ${filePath}`,
193
- recommendation: 'CHECK SECTION NAME'
194
- };
195
- }
196
-
197
- // Compute content hash for cache invalidation
198
- const sectionHash = crypto.createHash('md5')
199
- .update(sectionLines.map(l => l.text).join('\n'))
200
- .digest('hex');
201
-
202
- // Compute embeddings (use cache if valid)
203
- let embeddings = [];
204
-
205
- if (cached &&
206
- cached.hash === sectionHash &&
207
- cached.embeddings &&
208
- cached.embeddings.length === sectionLines.length) {
209
- embeddings = cached.embeddings;
210
- } else {
211
- for (const item of sectionLines) {
212
- const emb = await getEmbedding(item.text);
213
- embeddings.push({ text: item.text, line: item.line, embedding: emb });
214
- }
215
-
216
- // Save cache with content hash
217
- fs.writeFileSync(cachePath, JSON.stringify({
218
- file: validatedPath,
219
- section: sectionName,
220
- model: 'Xenova/all-MiniLM-L6-v2',
221
- hash: sectionHash,
222
- updated: new Date().toISOString(),
223
- embeddings
224
- }));
225
- }
226
-
227
- // Get new text embedding
228
- const newEmbedding = await getEmbedding(newText);
229
-
230
- // Calculate similarities
231
- const similarities = embeddings.map(item => ({
232
- text: item.text,
233
- line: item.line,
234
- similarity: cosineSimilarity(newEmbedding, item.embedding)
235
- }));
236
-
237
- // Sort by similarity and get top matches (threshold 0.65)
238
- similarities.sort((a, b) => b.similarity - a.similarity);
239
- const topMatches = similarities.slice(0, 5).filter(m => m.similarity >= 0.65);
240
-
241
- if (topMatches.length === 0) {
242
- return {
243
- stage: 2,
244
- matches: [],
245
- max_similarity: similarities[0]?.similarity || 0,
246
- recommendation: 'DIFFERENT (no similar content found)'
247
- };
248
- }
249
-
250
- const maxSim = topMatches[0].similarity;
251
- const overallRec = getRecommendation(maxSim);
252
-
253
- return {
254
- stage: 2,
255
- matches: topMatches.map(m => ({
256
- similarity: parseFloat(m.similarity.toFixed(3)),
257
- line: m.line,
258
- text: m.text.substring(0, 80) + (m.text.length > 80 ? '...' : ''),
259
- recommendation: getRecommendation(m.similarity)
260
- })),
261
- max_similarity: parseFloat(maxSim.toFixed(3)),
262
- recommendation: overallRec
263
- };
264
- }
265
-
266
- /**
267
- * Clear cache
268
- */
269
- function clearCache() {
270
- const cacheDir = path.join(process.cwd(), '.genie', '.cache', 'embeddings');
271
- if (fs.existsSync(cacheDir)) {
272
- const files = fs.readdirSync(cacheDir);
273
- for (const file of files) {
274
- fs.unlinkSync(path.join(cacheDir, file));
275
- }
276
- console.log(`Cleared ${files.length} cached embeddings`);
277
- } else {
278
- console.log('No cache to clear');
279
- }
280
- }
281
-
282
- /**
283
- * Main
284
- */
285
- async function main() {
286
- const args = process.argv.slice(2);
287
-
288
- // Help flag
289
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
290
- console.log('Usage:');
291
- console.log(' genie helper embeddings "new learning text" file.md "Section Name"');
292
- console.log('');
293
- console.log('Purpose: Check if new learning already exists in target section');
294
- console.log('');
295
- console.log('Output: Top matches with similarity scores and recommendations');
296
- console.log(' 0.85+ = DUPLICATE (merge or skip)');
297
- console.log(' 0.70-0.85 = RELATED (evaluate carefully)');
298
- console.log(' <0.70 = DIFFERENT (safe to append)');
299
- console.log('');
300
- console.log('Commands:');
301
- console.log(' genie helper embeddings "text" file.md "Section" # Check for duplicates');
302
- console.log(' genie helper embeddings clear-cache # Clear cache');
303
- console.log('');
304
- console.log('Example:');
305
- console.log(' genie helper embeddings \\');
306
- console.log(' "Never rewrite entire sections" \\');
307
- console.log(' .genie/spells/learn.md \\');
308
- console.log(' "Grow-and-Refine Protocol"');
309
- return;
310
- }
311
-
312
- // Clear cache command
313
- if (args[0] === 'clear-cache') {
314
- clearCache();
315
- return;
316
- }
317
-
318
- // Default: compare text to section
319
- const text = args[0];
320
- const file = args[1] || '.genie/spells/learn.md';
321
- const section = args[2] || 'Grow-and-Refine Protocol';
322
-
323
- if (!text) {
324
- console.error('Usage: genie helper embeddings "text" [file.md] ["Section Name"]');
325
- console.error(' Defaults: file=.genie/spells/learn.md, section="Grow-and-Refine Protocol"');
326
- process.exit(1);
327
- }
328
-
329
- if (!fs.existsSync(file)) {
330
- console.error(`File not found: ${file}`);
331
- process.exit(1);
332
- }
333
-
334
- const result = await compareToSection(text, file, section);
335
- console.log(JSON.stringify(result, null, 2));
336
- }
337
-
338
- main().catch(err => {
339
- console.error('ERROR:', err.message);
340
- if (err.stack) {
341
- console.error(err.stack);
342
- }
343
- process.exit(1);
344
- });
@@ -1,158 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Find Empty Sections Helper
5
- *
6
- * Detect markdown headings with no content (heading followed immediately by another heading or EOF).
7
- * These are placeholder sections that were never filled in.
8
- *
9
- * Usage:
10
- * node find-empty-sections.js <file-path> # Check single file
11
- * node find-empty-sections.js <directory> # Check all .md files recursively
12
- *
13
- * Output:
14
- * <file>:<line>: Empty section "Heading Text"
15
- */
16
-
17
- const fs = require('fs');
18
- const path = require('path');
19
-
20
- /**
21
- * Detect empty sections in file content
22
- * Returns: [{ line, heading }]
23
- */
24
- function detectEmptySections(content) {
25
- const lines = content.split('\n');
26
- const issues = [];
27
-
28
- for (let i = 0; i < lines.length; i++) {
29
- const line = lines[i].trim();
30
-
31
- // Check if this is a heading (starts with #)
32
- if (/^#+\s+.+/.test(line)) {
33
- const heading = line.replace(/^#+\s+/, '');
34
- let hasContent = false;
35
-
36
- // Look ahead for content until next heading or EOF
37
- for (let j = i + 1; j < lines.length; j++) {
38
- const nextLine = lines[j].trim();
39
-
40
- // Found another heading - section is empty
41
- if (/^#+\s+/.test(nextLine)) {
42
- break;
43
- }
44
-
45
- // Found non-empty content - section has content
46
- if (nextLine.length > 0) {
47
- hasContent = true;
48
- break;
49
- }
50
- }
51
-
52
- // If we reached EOF or next heading without finding content, it's empty
53
- if (!hasContent) {
54
- issues.push({
55
- line: i + 1,
56
- heading,
57
- });
58
- }
59
- }
60
- }
61
-
62
- return issues;
63
- }
64
-
65
- /**
66
- * Check single file
67
- */
68
- function checkFile(filePath) {
69
- try {
70
- const content = fs.readFileSync(filePath, 'utf-8');
71
- const issues = detectEmptySections(content);
72
-
73
- return issues.map(issue => ({
74
- file: filePath,
75
- line: issue.line,
76
- heading: issue.heading,
77
- }));
78
- } catch (err) {
79
- return [{ file: filePath, error: `Failed to read file: ${err.message}` }];
80
- }
81
- }
82
-
83
- /**
84
- * Check all .md files in directory
85
- */
86
- function checkDirectory(dirPath) {
87
- const allIssues = [];
88
-
89
- function scanDir(dir) {
90
- const entries = fs.readdirSync(dir, { withFileTypes: true });
91
-
92
- entries.forEach(entry => {
93
- const fullPath = path.join(dir, entry.name);
94
-
95
- if (entry.isDirectory() && !entry.name.startsWith('.')) {
96
- scanDir(fullPath);
97
- } else if (entry.isFile() && entry.name.endsWith('.md')) {
98
- const issues = checkFile(fullPath);
99
- allIssues.push(...issues);
100
- }
101
- });
102
- }
103
-
104
- scanDir(dirPath);
105
- return allIssues;
106
- }
107
-
108
- /**
109
- * Main
110
- */
111
- function main() {
112
- const args = process.argv.slice(2);
113
-
114
- if (args.length === 0) {
115
- console.error(`
116
- Usage:
117
- node find-empty-sections.js <file-path> # Check single file
118
- node find-empty-sections.js <directory> # Check all .md files recursively
119
-
120
- Output:
121
- <file>:<line>: Empty section "Heading Text"
122
-
123
- Exit code:
124
- 0 = No empty sections found
125
- 1 = Empty sections found
126
- `);
127
- process.exit(1);
128
- }
129
-
130
- const target = args[0];
131
-
132
- if (!fs.existsSync(target)) {
133
- console.error(`Error: Path not found: ${target}`);
134
- process.exit(1);
135
- }
136
-
137
- const stat = fs.statSync(target);
138
- const issues = stat.isDirectory()
139
- ? checkDirectory(target)
140
- : checkFile(target);
141
-
142
- if (issues.length === 0) {
143
- console.log('No empty sections found');
144
- process.exit(0);
145
- }
146
-
147
- issues.forEach(issue => {
148
- if (issue.line) {
149
- console.log(`${issue.file}:${issue.line}: Empty section "${issue.heading}"`);
150
- } else {
151
- console.log(`${issue.file}: ${issue.error}`);
152
- }
153
- });
154
-
155
- process.exit(1);
156
- }
157
-
158
- main();