pgserve 2.1.3 → 2.2.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.
- package/CHANGELOG.md +96 -0
- package/README.md +105 -1
- package/bin/autopg-wrapper.cjs +16 -0
- package/bin/pgserve-wrapper.cjs +32 -6
- package/bin/postgres-server.js +56 -0
- package/console/README.md +131 -0
- package/console/api.js +173 -0
- package/console/app.jsx +483 -0
- package/console/colors_and_type.css +227 -0
- package/console/components.jsx +167 -0
- package/console/console.css +1666 -0
- package/console/data.jsx +350 -0
- package/console/index.html +31 -0
- package/console/screens/databases.jsx +5 -0
- package/console/screens/health.jsx +5 -0
- package/console/screens/ingress.jsx +5 -0
- package/console/screens/optimizer.jsx +5 -0
- package/console/screens/rlm-sim.jsx +5 -0
- package/console/screens/rlm-trace.jsx +5 -0
- package/console/screens/security.jsx +5 -0
- package/console/screens/settings.jsx +611 -0
- package/console/screens/sql.jsx +5 -0
- package/console/screens/sync.jsx +5 -0
- package/console/screens/tables.jsx +5 -0
- package/console/tweaks-panel.jsx +425 -0
- package/package.json +14 -2
- package/scripts/postinstall.cjs +60 -0
- package/src/cli-config.cjs +310 -0
- package/src/cli-install.cjs +112 -11
- package/src/cli-restart.cjs +228 -0
- package/src/cli-ui.cjs +580 -0
- package/src/cluster.js +43 -38
- package/src/postgres.js +141 -19
- package/src/settings-loader.cjs +235 -0
- package/src/settings-migrate.cjs +212 -0
- package/src/settings-pg-args.cjs +146 -0
- package/src/settings-schema.cjs +422 -0
- package/src/settings-validator.cjs +416 -0
- package/src/settings-writer.cjs +288 -0
- package/src/upgrade/index.js +65 -0
- package/src/upgrade/runner.js +23 -0
- package/src/upgrade/steps/binary-cache-flush.js +67 -0
- package/src/upgrade/steps/consumer-signal.js +40 -0
- package/src/upgrade/steps/env-refresh.js +89 -0
- package/src/upgrade/steps/health-validate.js +53 -0
- package/src/upgrade/steps/plpgsql-resolve.js +66 -0
- package/src/upgrade/steps/port-reconcile.js +52 -0
- package/.claude/context/windows-debug.md +0 -119
- package/.genie/AGENTS.md +0 -15
- package/.genie/agents/README.md +0 -110
- package/.genie/agents/analyze.md +0 -176
- package/.genie/agents/forge.md +0 -290
- package/.genie/agents/garbage-cleaner.md +0 -324
- package/.genie/agents/garbage-collector.md +0 -596
- package/.genie/agents/github-issue-gc.md +0 -618
- package/.genie/agents/review.md +0 -380
- package/.genie/agents/semantic-analyzer/find-duplicates.md +0 -90
- package/.genie/agents/semantic-analyzer/find-orphans.md +0 -99
- package/.genie/agents/semantic-analyzer.md +0 -101
- package/.genie/agents/update.md +0 -182
- package/.genie/agents/wish.md +0 -357
- package/.genie/brainstorms/pgserve-v2/DESIGN.md +0 -174
- package/.genie/code/AGENTS.md +0 -694
- package/.genie/code/agents/audit/risk.md +0 -173
- package/.genie/code/agents/audit/security.md +0 -189
- package/.genie/code/agents/audit.md +0 -145
- package/.genie/code/agents/challenge.md +0 -230
- package/.genie/code/agents/change-reviewer.md +0 -295
- package/.genie/code/agents/code-garbage-collector.md +0 -425
- package/.genie/code/agents/code-quality.md +0 -410
- package/.genie/code/agents/commit-suggester.md +0 -255
- package/.genie/code/agents/commit.md +0 -124
- package/.genie/code/agents/consensus.md +0 -204
- package/.genie/code/agents/daily-standup.md +0 -722
- package/.genie/code/agents/docgen.md +0 -48
- package/.genie/code/agents/explore.md +0 -79
- package/.genie/code/agents/fix.md +0 -100
- package/.genie/code/agents/git/commit-advisory.md +0 -219
- package/.genie/code/agents/git/workflows/issue.md +0 -244
- package/.genie/code/agents/git/workflows/pr.md +0 -179
- package/.genie/code/agents/git/workflows/release.md +0 -460
- package/.genie/code/agents/git/workflows/report.md +0 -342
- package/.genie/code/agents/git.md +0 -432
- package/.genie/code/agents/implementor.md +0 -161
- package/.genie/code/agents/install.md +0 -515
- package/.genie/code/agents/issue-creator.md +0 -344
- package/.genie/code/agents/polish.md +0 -116
- package/.genie/code/agents/qa.md +0 -653
- package/.genie/code/agents/refactor.md +0 -294
- package/.genie/code/agents/release.md +0 -1129
- package/.genie/code/agents/roadmap.md +0 -885
- package/.genie/code/agents/tests.md +0 -557
- package/.genie/code/agents/tracer.md +0 -50
- package/.genie/code/agents/update/upstream-update.md +0 -85
- package/.genie/code/agents/update/versions/generic-update.md +0 -305
- package/.genie/code/agents/vibe.md +0 -1317
- package/.genie/code/spells/agent-configuration.md +0 -58
- package/.genie/code/spells/automated-rc-publishing.md +0 -106
- package/.genie/code/spells/branch-tracker-guidance.md +0 -28
- package/.genie/code/spells/debug.md +0 -320
- package/.genie/code/spells/emoji-naming-convention.md +0 -303
- package/.genie/code/spells/evidence-storage.md +0 -26
- package/.genie/code/spells/file-naming-rules.md +0 -35
- package/.genie/code/spells/forge-code-blueprints.md +0 -195
- package/.genie/code/spells/genie-integration.md +0 -153
- package/.genie/code/spells/publishing-protocol.md +0 -61
- package/.genie/code/spells/team-consultation-protocol.md +0 -284
- package/.genie/code/spells/tool-requirements.md +0 -20
- package/.genie/code/spells/triad-maintenance-protocol.md +0 -154
- package/.genie/code/teams/tech-council/council.md +0 -328
- package/.genie/code/teams/tech-council/jt.md +0 -352
- package/.genie/code/teams/tech-council/nayr.md +0 -305
- package/.genie/code/teams/tech-council/oettam.md +0 -375
- package/.genie/neurons/README.md +0 -193
- package/.genie/neurons/forge.md +0 -106
- package/.genie/neurons/genie.md +0 -63
- package/.genie/neurons/review.md +0 -106
- package/.genie/neurons/wish.md +0 -104
- package/.genie/product/README.md +0 -20
- package/.genie/product/cli-automation.md +0 -359
- package/.genie/product/environment.md +0 -60
- package/.genie/product/mission.md +0 -60
- package/.genie/product/roadmap.md +0 -44
- package/.genie/product/tech-stack.md +0 -34
- package/.genie/product/templates/context-template.md +0 -218
- package/.genie/product/templates/qa-done-report-template.md +0 -68
- package/.genie/product/templates/review-report-template.md +0 -89
- package/.genie/product/templates/wish-template.md +0 -120
- package/.genie/scripts/helpers/analyze-commit.js +0 -195
- package/.genie/scripts/helpers/bullet-counter.js +0 -194
- package/.genie/scripts/helpers/bullet-find.js +0 -289
- package/.genie/scripts/helpers/bullet-id.js +0 -244
- package/.genie/scripts/helpers/check-secrets.js +0 -237
- package/.genie/scripts/helpers/count-tokens.js +0 -200
- package/.genie/scripts/helpers/create-frontmatter.js +0 -456
- package/.genie/scripts/helpers/detect-markers.js +0 -293
- package/.genie/scripts/helpers/detect-todos.js +0 -267
- package/.genie/scripts/helpers/detect-unlabeled-blocks.js +0 -135
- package/.genie/scripts/helpers/embeddings.js +0 -344
- package/.genie/scripts/helpers/find-empty-sections.js +0 -158
- package/.genie/scripts/helpers/index.js +0 -319
- package/.genie/scripts/helpers/validate-frontmatter.js +0 -578
- package/.genie/scripts/helpers/validate-links.js +0 -207
- package/.genie/scripts/helpers/validate-paths.js +0 -373
- package/.genie/spells/README.md +0 -9
- package/.genie/spells/ace-protocol.md +0 -118
- package/.genie/spells/ask-one-at-a-time.md +0 -175
- package/.genie/spells/backup-analyzer.md +0 -542
- package/.genie/spells/blocker.md +0 -12
- package/.genie/spells/break-things-move-fast.md +0 -56
- package/.genie/spells/context-candidates.md +0 -72
- package/.genie/spells/context-critic.md +0 -51
- package/.genie/spells/defer-to-expertise.md +0 -278
- package/.genie/spells/delegate-dont-do.md +0 -292
- package/.genie/spells/error-investigation-protocol.md +0 -328
- package/.genie/spells/evidence-based-completion.md +0 -273
- package/.genie/spells/experiment.md +0 -65
- package/.genie/spells/file-creation-protocol.md +0 -229
- package/.genie/spells/forge-integration.md +0 -281
- package/.genie/spells/forge-orchestration.md +0 -514
- package/.genie/spells/gather-context.md +0 -18
- package/.genie/spells/global-health-check.md +0 -34
- package/.genie/spells/global-noop-roundtrip.md +0 -25
- package/.genie/spells/install-genie.md +0 -1232
- package/.genie/spells/install.md +0 -82
- package/.genie/spells/investigate-before-commit.md +0 -112
- package/.genie/spells/know-yourself.md +0 -288
- package/.genie/spells/learn.md +0 -828
- package/.genie/spells/mcp-diagnostic-protocol.md +0 -246
- package/.genie/spells/mcp-first.md +0 -124
- package/.genie/spells/multi-step-execution.md +0 -67
- package/.genie/spells/orchestration-boundary-protocol.md +0 -256
- package/.genie/spells/orchestrator-not-implementor.md +0 -189
- package/.genie/spells/prompt.md +0 -746
- package/.genie/spells/reflect.md +0 -404
- package/.genie/spells/routing-decision-matrix.md +0 -368
- package/.genie/spells/run-in-parallel.md +0 -12
- package/.genie/spells/session-state-updater-example.md +0 -196
- package/.genie/spells/session-state-updater.md +0 -220
- package/.genie/spells/track-long-running-tasks.md +0 -133
- package/.genie/spells/troubleshoot-infrastructure.md +0 -176
- package/.genie/spells/upgrade-genie.md +0 -415
- package/.genie/spells/url-presentation-protocol.md +0 -301
- package/.genie/spells/wish-initiation.md +0 -158
- package/.genie/spells/wish-issue-linkage.md +0 -410
- package/.genie/spells/wish-lifecycle.md +0 -100
- package/.genie/state/provider-status.json +0 -3
- package/.genie/state/version.json +0 -16
- package/.genie/wishes/canonical-pgserve-pm2-supervision/WISH.md +0 -290
- package/.genie/wishes/pgserve-v2/BRIEF-from-genie-pgserve.md +0 -99
- package/.genie/wishes/pgserve-v2/WISH.md +0 -442
- package/.genie/wishes/release-system-genie-pattern/WISH.md +0 -268
- package/.genie/wishes/release-system-genie-pattern/validation.md +0 -205
- package/.gitguardian.yaml +0 -29
- package/.gitguardianignore +0 -16
- package/.github/workflows/ci.yml +0 -122
- package/.github/workflows/release.yml +0 -289
- package/.github/workflows/version.yml +0 -228
- package/.husky/pre-commit +0 -2
- package/AGENTS.md +0 -433
- package/CLAUDE.md +0 -1
- package/Makefile +0 -285
- package/assets/icon.ico +0 -0
- package/bun.lock +0 -435
- package/bunfig.toml +0 -28
- package/ecosystem.config.cjs +0 -23
- package/eslint.config.js +0 -63
- package/examples/multi-tenant-demo.js +0 -104
- package/install.sh +0 -123
- package/knip.json +0 -9
- package/tests/audit.test.js +0 -189
- package/tests/backpressure.test.js +0 -167
- package/tests/benchmarks/runner.js +0 -1197
- package/tests/benchmarks/vector-generator.js +0 -368
- package/tests/cli-install.test.js +0 -322
- package/tests/control-db.test.js +0 -285
- package/tests/daemon-args.test.js +0 -86
- package/tests/daemon-control.test.js +0 -171
- package/tests/daemon-fingerprint-integration.test.js +0 -111
- package/tests/daemon-pr24-regression.test.js +0 -198
- package/tests/fingerprint.test.js +0 -263
- package/tests/fixtures/240-orphan-seed.sql +0 -30
- package/tests/multi-tenant.test.js +0 -374
- package/tests/orphan-cleanup.test.js +0 -390
- package/tests/pg-version-regex.test.js +0 -129
- package/tests/quick-bench.js +0 -135
- package/tests/router-handshake-retry.test.js +0 -119
- package/tests/router-handshake-watchdog.test.js +0 -110
- package/tests/sdk.test.js +0 -71
- package/tests/stale-postmaster-pid.test.js +0 -85
- package/tests/stress-test.js +0 -439
- package/tests/sync-perf-test.js +0 -150
- package/tests/tcp-listen.test.js +0 -368
- package/tests/tenancy.test.js +0 -403
- package/tests/wrapper-supervision.test.js +0 -107
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bullet Counter Updater
|
|
5
|
-
*
|
|
6
|
-
* Find and update helpful/harmful counters for learning bullets.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* genie helper bullet-counter ID --helpful
|
|
10
|
-
* genie helper bullet-counter ID --harmful
|
|
11
|
-
* genie helper bullet-counter ID (show current counters)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const fs = require('fs');
|
|
15
|
-
const path = require('path');
|
|
16
|
-
const { exec } = require('child_process');
|
|
17
|
-
const { promisify } = require('util');
|
|
18
|
-
|
|
19
|
-
const execAsync = promisify(exec);
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Find bullet by ID across all markdown files
|
|
23
|
-
* Returns: { file, line, content, helpful, harmful }
|
|
24
|
-
*/
|
|
25
|
-
function findBullet(id) {
|
|
26
|
-
const searchPath = path.join(process.cwd(), '.genie');
|
|
27
|
-
|
|
28
|
-
// Use ripgrep to find the bullet
|
|
29
|
-
const pattern = `^- \\[${id}\\] helpful=(\\d+) harmful=(\\d+):`;
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
const { execSync } = require('child_process');
|
|
33
|
-
const result = execSync(
|
|
34
|
-
`rg -n "${pattern}" "${searchPath}"`,
|
|
35
|
-
{ encoding: 'utf-8' }
|
|
36
|
-
).trim();
|
|
37
|
-
|
|
38
|
-
if (!result) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Parse result: file:line:content
|
|
43
|
-
const match = result.match(/^([^:]+):(\d+):(.+)$/);
|
|
44
|
-
if (!match) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const [, file, lineNum, content] = match;
|
|
49
|
-
|
|
50
|
-
// Extract counters from content
|
|
51
|
-
const counterMatch = content.match(/helpful=(\d+) harmful=(\d+)/);
|
|
52
|
-
if (!counterMatch) {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
file: file,
|
|
58
|
-
line: parseInt(lineNum, 10),
|
|
59
|
-
content: content,
|
|
60
|
-
helpful: parseInt(counterMatch[1], 10),
|
|
61
|
-
harmful: parseInt(counterMatch[2], 10)
|
|
62
|
-
};
|
|
63
|
-
} catch (err) {
|
|
64
|
-
// rg returns exit code 1 when no matches found
|
|
65
|
-
if (err.status === 1) {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
throw err;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Update bullet counter in file
|
|
74
|
-
*/
|
|
75
|
-
function updateBulletCounter(bullet, incrementHelpful, incrementHarmful) {
|
|
76
|
-
const newHelpful = bullet.helpful + (incrementHelpful ? 1 : 0);
|
|
77
|
-
const newHarmful = bullet.harmful + (incrementHarmful ? 1 : 0);
|
|
78
|
-
|
|
79
|
-
// Read file
|
|
80
|
-
const content = fs.readFileSync(bullet.file, 'utf-8');
|
|
81
|
-
const lines = content.split('\n');
|
|
82
|
-
|
|
83
|
-
// Update the line (1-indexed to 0-indexed)
|
|
84
|
-
const lineIndex = bullet.line - 1;
|
|
85
|
-
const oldLine = lines[lineIndex];
|
|
86
|
-
|
|
87
|
-
// Replace counters in the line
|
|
88
|
-
const newLine = oldLine.replace(
|
|
89
|
-
/helpful=(\d+) harmful=(\d+)/,
|
|
90
|
-
`helpful=${newHelpful} harmful=${newHarmful}`
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
if (oldLine === newLine) {
|
|
94
|
-
console.error('Warning: No change detected');
|
|
95
|
-
return bullet;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Write updated content
|
|
99
|
-
lines[lineIndex] = newLine;
|
|
100
|
-
fs.writeFileSync(bullet.file, lines.join('\n'));
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
...bullet,
|
|
104
|
-
content: newLine,
|
|
105
|
-
helpful: newHelpful,
|
|
106
|
-
harmful: newHarmful
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Display bullet info
|
|
112
|
-
*/
|
|
113
|
-
function displayBullet(bullet) {
|
|
114
|
-
console.log(JSON.stringify({
|
|
115
|
-
file: path.relative(process.cwd(), bullet.file),
|
|
116
|
-
line: bullet.line,
|
|
117
|
-
helpful: bullet.helpful,
|
|
118
|
-
harmful: bullet.harmful,
|
|
119
|
-
content: bullet.content.trim()
|
|
120
|
-
}, null, 2));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Main CLI
|
|
125
|
-
*/
|
|
126
|
-
async function main() {
|
|
127
|
-
const args = process.argv.slice(2);
|
|
128
|
-
|
|
129
|
-
// Help
|
|
130
|
-
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
131
|
-
console.log('Usage:');
|
|
132
|
-
console.log(' genie helper bullet-counter ID');
|
|
133
|
-
console.log(' Show current counters for bullet');
|
|
134
|
-
console.log('');
|
|
135
|
-
console.log(' genie helper bullet-counter ID --helpful');
|
|
136
|
-
console.log(' Increment helpful counter');
|
|
137
|
-
console.log('');
|
|
138
|
-
console.log(' genie helper bullet-counter ID --harmful');
|
|
139
|
-
console.log(' Increment harmful counter');
|
|
140
|
-
console.log('');
|
|
141
|
-
console.log('Examples:');
|
|
142
|
-
console.log(' $ genie helper bullet-counter learn-042');
|
|
143
|
-
console.log(' {');
|
|
144
|
-
console.log(' "file": ".genie/spells/learn.md",');
|
|
145
|
-
console.log(' "line": 356,');
|
|
146
|
-
console.log(' "helpful": 5,');
|
|
147
|
-
console.log(' "harmful": 0');
|
|
148
|
-
console.log(' }');
|
|
149
|
-
console.log('');
|
|
150
|
-
console.log(' $ genie helper bullet-counter learn-042 --helpful');
|
|
151
|
-
console.log(' Updated: helpful=6 harmful=0');
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const id = args[0];
|
|
156
|
-
const incrementHelpful = args.includes('--helpful');
|
|
157
|
-
const incrementHarmful = args.includes('--harmful');
|
|
158
|
-
|
|
159
|
-
if (!id) {
|
|
160
|
-
console.error('Error: Bullet ID required');
|
|
161
|
-
console.error('Usage: genie helper bullet-counter ID [--helpful|--harmful]');
|
|
162
|
-
process.exit(1);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Find bullet
|
|
166
|
-
const bullet = findBullet(id);
|
|
167
|
-
|
|
168
|
-
if (!bullet) {
|
|
169
|
-
console.error(`Error: Bullet [${id}] not found`);
|
|
170
|
-
console.error('');
|
|
171
|
-
console.error('Searched in: .genie/');
|
|
172
|
-
console.error('Pattern: - [ID] helpful=N harmful=M: content');
|
|
173
|
-
console.error('');
|
|
174
|
-
console.error('Tip: Use "genie helper bullet-find" to search for bullets');
|
|
175
|
-
process.exit(1);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Show current state
|
|
179
|
-
if (!incrementHelpful && !incrementHarmful) {
|
|
180
|
-
displayBullet(bullet);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Update counter
|
|
185
|
-
const updated = updateBulletCounter(bullet, incrementHelpful, incrementHarmful);
|
|
186
|
-
|
|
187
|
-
console.log(`Updated: helpful=${updated.helpful} harmful=${updated.harmful}`);
|
|
188
|
-
console.log(`File: ${path.relative(process.cwd(), updated.file)}:${updated.line}`);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
main().catch(err => {
|
|
192
|
-
console.error('ERROR:', err.message);
|
|
193
|
-
process.exit(1);
|
|
194
|
-
});
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bullet Retrieval Tool
|
|
5
|
-
*
|
|
6
|
-
* Find and query structured learning bullets.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* genie helper bullet-find ID
|
|
10
|
-
* genie helper bullet-find --top-helpful --limit=10
|
|
11
|
-
* genie helper bullet-find --top-harmful --limit=10
|
|
12
|
-
* genie helper bullet-find --file=learn.md --section="Section"
|
|
13
|
-
* genie helper bullet-find --search="keyword"
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
const { execSync } = require('child_process');
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Parse bullet line into structured data
|
|
22
|
-
*/
|
|
23
|
-
function parseBullet(line, file, lineNum) {
|
|
24
|
-
const match = line.match(/^- \[([a-z]+-\d{3})\] helpful=(\d+) harmful=(\d+): (.+)$/);
|
|
25
|
-
|
|
26
|
-
if (!match) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return {
|
|
31
|
-
id: match[1],
|
|
32
|
-
helpful: parseInt(match[2], 10),
|
|
33
|
-
harmful: parseInt(match[3], 10),
|
|
34
|
-
content: match[4],
|
|
35
|
-
file: path.relative(process.cwd(), file),
|
|
36
|
-
line: lineNum
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Find bullet by ID
|
|
42
|
-
*/
|
|
43
|
-
function findById(id) {
|
|
44
|
-
try {
|
|
45
|
-
const result = execSync(
|
|
46
|
-
`rg -n "^- \\[${id}\\]" .genie/`,
|
|
47
|
-
{ encoding: 'utf-8', cwd: process.cwd() }
|
|
48
|
-
).trim();
|
|
49
|
-
|
|
50
|
-
if (!result) {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Parse: file:line:content
|
|
55
|
-
const match = result.match(/^([^:]+):(\d+):(.+)$/);
|
|
56
|
-
if (!match) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const [, file, lineNum, content] = match;
|
|
61
|
-
return parseBullet(content, file, parseInt(lineNum, 10));
|
|
62
|
-
} catch (err) {
|
|
63
|
-
if (err.status === 1) {
|
|
64
|
-
return null; // Not found
|
|
65
|
-
}
|
|
66
|
-
throw err;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Find all bullets in framework
|
|
72
|
-
*/
|
|
73
|
-
function findAllBullets() {
|
|
74
|
-
try {
|
|
75
|
-
const result = execSync(
|
|
76
|
-
'rg -n "^- \\[[a-z]+-\\d{3}\\] helpful=\\d+ harmful=\\d+:" .genie/',
|
|
77
|
-
{ encoding: 'utf-8', cwd: process.cwd() }
|
|
78
|
-
).trim();
|
|
79
|
-
|
|
80
|
-
if (!result) {
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const lines = result.split('\n');
|
|
85
|
-
const bullets = [];
|
|
86
|
-
|
|
87
|
-
for (const line of lines) {
|
|
88
|
-
const match = line.match(/^([^:]+):(\d+):(.+)$/);
|
|
89
|
-
if (match) {
|
|
90
|
-
const [, file, lineNum, content] = match;
|
|
91
|
-
const bullet = parseBullet(content, file, parseInt(lineNum, 10));
|
|
92
|
-
if (bullet) {
|
|
93
|
-
bullets.push(bullet);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return bullets;
|
|
99
|
-
} catch (err) {
|
|
100
|
-
if (err.status === 1) {
|
|
101
|
-
return []; // None found
|
|
102
|
-
}
|
|
103
|
-
throw err;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Find bullets in specific file
|
|
109
|
-
*/
|
|
110
|
-
function findInFile(filePath) {
|
|
111
|
-
const fullPath = path.resolve(process.cwd(), filePath);
|
|
112
|
-
|
|
113
|
-
if (!fs.existsSync(fullPath)) {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
try {
|
|
118
|
-
const result = execSync(
|
|
119
|
-
`rg -n "^- \\[[a-z]+-\\d{3}\\] helpful=\\d+ harmful=\\d+:" "${fullPath}"`,
|
|
120
|
-
{ encoding: 'utf-8' }
|
|
121
|
-
).trim();
|
|
122
|
-
|
|
123
|
-
if (!result) {
|
|
124
|
-
return [];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const lines = result.split('\n');
|
|
128
|
-
const bullets = [];
|
|
129
|
-
|
|
130
|
-
for (const line of lines) {
|
|
131
|
-
// When rg searches a single file, output is "line:content" not "file:line:content"
|
|
132
|
-
const match = line.match(/^(\d+):(.+)$/);
|
|
133
|
-
if (match) {
|
|
134
|
-
const [, lineNum, content] = match;
|
|
135
|
-
const bullet = parseBullet(content, fullPath, parseInt(lineNum, 10));
|
|
136
|
-
if (bullet) {
|
|
137
|
-
bullets.push(bullet);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return bullets;
|
|
143
|
-
} catch (err) {
|
|
144
|
-
if (err.status === 1) {
|
|
145
|
-
return []; // None found
|
|
146
|
-
}
|
|
147
|
-
throw err;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Search bullets by content keyword
|
|
153
|
-
*/
|
|
154
|
-
function searchByKeyword(keyword) {
|
|
155
|
-
const allBullets = findAllBullets();
|
|
156
|
-
return allBullets.filter(b =>
|
|
157
|
-
b.content.toLowerCase().includes(keyword.toLowerCase()) ||
|
|
158
|
-
b.id.includes(keyword)
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get top N bullets by helpful count
|
|
164
|
-
*/
|
|
165
|
-
function getTopHelpful(limit = 10) {
|
|
166
|
-
const bullets = findAllBullets();
|
|
167
|
-
bullets.sort((a, b) => b.helpful - a.helpful);
|
|
168
|
-
return bullets.slice(0, limit);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Get top N bullets by harmful count
|
|
173
|
-
*/
|
|
174
|
-
function getTopHarmful(limit = 10) {
|
|
175
|
-
const bullets = findAllBullets();
|
|
176
|
-
bullets.sort((a, b) => b.harmful - a.harmful);
|
|
177
|
-
return bullets.slice(0, limit);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Display bullets
|
|
182
|
-
*/
|
|
183
|
-
function displayBullets(bullets, title = null) {
|
|
184
|
-
if (title) {
|
|
185
|
-
console.log(`\n${title}\n${'='.repeat(title.length)}\n`);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (bullets.length === 0) {
|
|
189
|
-
console.log('No bullets found');
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
for (const bullet of bullets) {
|
|
194
|
-
console.log(`[${bullet.id}] helpful=${bullet.helpful} harmful=${bullet.harmful}`);
|
|
195
|
-
console.log(` ${bullet.file}:${bullet.line}`);
|
|
196
|
-
console.log(` ${bullet.content.substring(0, 100)}${bullet.content.length > 100 ? '...' : ''}`);
|
|
197
|
-
console.log('');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
console.log(`Total: ${bullets.length} bullet(s)`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Main CLI
|
|
205
|
-
*/
|
|
206
|
-
async function main() {
|
|
207
|
-
const args = process.argv.slice(2);
|
|
208
|
-
|
|
209
|
-
// Help
|
|
210
|
-
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
211
|
-
console.log('Usage:');
|
|
212
|
-
console.log(' genie helper bullet-find ID');
|
|
213
|
-
console.log(' Find specific bullet by ID');
|
|
214
|
-
console.log('');
|
|
215
|
-
console.log(' genie helper bullet-find --top-helpful --limit=10');
|
|
216
|
-
console.log(' Find top 10 most helpful bullets');
|
|
217
|
-
console.log('');
|
|
218
|
-
console.log(' genie helper bullet-find --top-harmful --limit=10');
|
|
219
|
-
console.log(' Find top 10 most harmful bullets');
|
|
220
|
-
console.log('');
|
|
221
|
-
console.log(' genie helper bullet-find --file=file.md');
|
|
222
|
-
console.log(' Find all bullets in specific file');
|
|
223
|
-
console.log('');
|
|
224
|
-
console.log(' genie helper bullet-find --search="keyword"');
|
|
225
|
-
console.log(' Search bullets by content');
|
|
226
|
-
console.log('');
|
|
227
|
-
console.log('Examples:');
|
|
228
|
-
console.log(' $ genie helper bullet-find learn-042');
|
|
229
|
-
console.log(' $ genie helper bullet-find --top-helpful --limit=5');
|
|
230
|
-
console.log(' $ genie helper bullet-find --search="delegate"');
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Find by ID
|
|
235
|
-
if (args[0] && !args[0].startsWith('--')) {
|
|
236
|
-
const bullet = findById(args[0]);
|
|
237
|
-
if (!bullet) {
|
|
238
|
-
console.error(`Error: Bullet [${args[0]}] not found`);
|
|
239
|
-
process.exit(1);
|
|
240
|
-
}
|
|
241
|
-
displayBullets([bullet]);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Top helpful
|
|
246
|
-
if (args.includes('--top-helpful')) {
|
|
247
|
-
const limitArg = args.find(a => a.startsWith('--limit='));
|
|
248
|
-
const limit = limitArg ? parseInt(limitArg.split('=')[1], 10) : 10;
|
|
249
|
-
const bullets = getTopHelpful(limit);
|
|
250
|
-
displayBullets(bullets, `Top ${limit} Most Helpful Bullets`);
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Top harmful
|
|
255
|
-
if (args.includes('--top-harmful')) {
|
|
256
|
-
const limitArg = args.find(a => a.startsWith('--limit='));
|
|
257
|
-
const limit = limitArg ? parseInt(limitArg.split('=')[1], 10) : 10;
|
|
258
|
-
const bullets = getTopHarmful(limit);
|
|
259
|
-
displayBullets(bullets, `Top ${limit} Most Harmful Bullets`);
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Find in file
|
|
264
|
-
const fileArg = args.find(a => a.startsWith('--file='));
|
|
265
|
-
if (fileArg) {
|
|
266
|
-
const filePath = fileArg.split('=')[1];
|
|
267
|
-
const bullets = findInFile(filePath);
|
|
268
|
-
displayBullets(bullets, `Bullets in ${filePath}`);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Search by keyword
|
|
273
|
-
const searchArg = args.find(a => a.startsWith('--search='));
|
|
274
|
-
if (searchArg) {
|
|
275
|
-
const keyword = searchArg.split('=')[1];
|
|
276
|
-
const bullets = searchByKeyword(keyword);
|
|
277
|
-
displayBullets(bullets, `Search results for "${keyword}"`);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
console.error('Error: No valid operation specified');
|
|
282
|
-
console.error('Use --help to see available options');
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
main().catch(err => {
|
|
287
|
-
console.error('ERROR:', err.message);
|
|
288
|
-
process.exit(1);
|
|
289
|
-
});
|
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Bullet ID Generator
|
|
5
|
-
*
|
|
6
|
-
* Generates unique IDs for structured learning bullets.
|
|
7
|
-
* Format: [prefix-NNN] where NNN is zero-padded 3-digit counter.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* genie helper bullet-id file.md
|
|
11
|
-
* genie helper bullet-id file.md --count=10
|
|
12
|
-
* genie helper bullet-id file.md --peek (show next without incrementing)
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const fs = require('fs');
|
|
16
|
-
const path = require('path');
|
|
17
|
-
|
|
18
|
-
// Maximum bullet ID number (supports 001-999)
|
|
19
|
-
const MAX_BULLET_ID = 999;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Extract prefix from filename
|
|
23
|
-
* learn.md → learn
|
|
24
|
-
* orchestration-boundary-protocol.md → orchestration
|
|
25
|
-
*/
|
|
26
|
-
function getFilePrefix(filePath) {
|
|
27
|
-
const basename = path.basename(filePath, '.md');
|
|
28
|
-
|
|
29
|
-
// For multi-word files, use first word
|
|
30
|
-
const firstWord = basename.split('-')[0];
|
|
31
|
-
|
|
32
|
-
// Lowercase for consistency
|
|
33
|
-
return firstWord.toLowerCase();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Get cache directory path
|
|
38
|
-
*/
|
|
39
|
-
function getCacheDir() {
|
|
40
|
-
const cacheDir = path.join(process.cwd(), '.genie', '.cache', 'bullet-ids');
|
|
41
|
-
if (!fs.existsSync(cacheDir)) {
|
|
42
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
43
|
-
}
|
|
44
|
-
return cacheDir;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Get cache file path for prefix
|
|
49
|
-
*/
|
|
50
|
-
function getCachePath(prefix) {
|
|
51
|
-
return path.join(getCacheDir(), `${prefix}.json`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Read last ID from cache
|
|
56
|
-
*/
|
|
57
|
-
function getLastIdFromCache(prefix) {
|
|
58
|
-
const cachePath = getCachePath(prefix);
|
|
59
|
-
|
|
60
|
-
if (!fs.existsSync(cachePath)) {
|
|
61
|
-
return 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
const cache = JSON.parse(fs.readFileSync(cachePath, 'utf-8'));
|
|
66
|
-
return cache.lastId || 0;
|
|
67
|
-
} catch (err) {
|
|
68
|
-
console.error(`Warning: Cache read failed for ${prefix}, starting from 0`);
|
|
69
|
-
return 0;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Scan file for highest existing ID
|
|
75
|
-
* Handles cases where file was manually edited
|
|
76
|
-
*/
|
|
77
|
-
function scanFileForHighestId(filePath, prefix) {
|
|
78
|
-
if (!fs.existsSync(filePath)) {
|
|
79
|
-
return 0;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
84
|
-
const pattern = new RegExp(`\\[${prefix}-(\\d{3})\\]`, 'g');
|
|
85
|
-
|
|
86
|
-
let highest = 0;
|
|
87
|
-
let match;
|
|
88
|
-
|
|
89
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
90
|
-
const idNum = parseInt(match[1], 10);
|
|
91
|
-
if (idNum > highest) {
|
|
92
|
-
highest = idNum;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return highest;
|
|
97
|
-
} catch (err) {
|
|
98
|
-
console.error(`Warning: Could not scan ${filePath}`);
|
|
99
|
-
return 0;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get next ID (reconciles cache and file scan)
|
|
105
|
-
*/
|
|
106
|
-
function getNextId(filePath, prefix) {
|
|
107
|
-
const cachedId = getLastIdFromCache(prefix);
|
|
108
|
-
const scannedId = scanFileForHighestId(filePath, prefix);
|
|
109
|
-
|
|
110
|
-
// Use whichever is higher (handles manual edits)
|
|
111
|
-
const lastId = Math.max(cachedId, scannedId);
|
|
112
|
-
|
|
113
|
-
return lastId + 1;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Save last ID to cache
|
|
118
|
-
*/
|
|
119
|
-
function saveIdToCache(prefix, lastId) {
|
|
120
|
-
const cachePath = getCachePath(prefix);
|
|
121
|
-
|
|
122
|
-
fs.writeFileSync(cachePath, JSON.stringify({
|
|
123
|
-
prefix,
|
|
124
|
-
lastId,
|
|
125
|
-
updated: new Date().toISOString()
|
|
126
|
-
}, null, 2));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Generate formatted ID
|
|
131
|
-
*/
|
|
132
|
-
function formatId(prefix, number) {
|
|
133
|
-
const paddedNum = String(number).padStart(3, '0');
|
|
134
|
-
return `${prefix}-${paddedNum}`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Generate single ID
|
|
139
|
-
*/
|
|
140
|
-
function generateSingleId(filePath, peek = false) {
|
|
141
|
-
const prefix = getFilePrefix(filePath);
|
|
142
|
-
const nextNum = getNextId(filePath, prefix);
|
|
143
|
-
|
|
144
|
-
if (nextNum > MAX_BULLET_ID) {
|
|
145
|
-
console.error(`ERROR: ID limit reached for ${prefix} (max ${MAX_BULLET_ID})`);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const id = formatId(prefix, nextNum);
|
|
150
|
-
|
|
151
|
-
// Save to cache unless peek mode
|
|
152
|
-
if (!peek) {
|
|
153
|
-
saveIdToCache(prefix, nextNum);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return id;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Generate batch of IDs
|
|
161
|
-
*/
|
|
162
|
-
function generateBatchIds(filePath, count) {
|
|
163
|
-
const prefix = getFilePrefix(filePath);
|
|
164
|
-
let nextNum = getNextId(filePath, prefix);
|
|
165
|
-
|
|
166
|
-
if (nextNum + count > MAX_BULLET_ID) {
|
|
167
|
-
console.error(`ERROR: Batch would exceed ID limit for ${prefix} (max ${MAX_BULLET_ID})`);
|
|
168
|
-
process.exit(1);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const ids = [];
|
|
172
|
-
for (let i = 0; i < count; i++) {
|
|
173
|
-
ids.push(formatId(prefix, nextNum + i));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Save final ID to cache
|
|
177
|
-
saveIdToCache(prefix, nextNum + count - 1);
|
|
178
|
-
|
|
179
|
-
return ids;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Main CLI
|
|
184
|
-
*/
|
|
185
|
-
async function main() {
|
|
186
|
-
const args = process.argv.slice(2);
|
|
187
|
-
|
|
188
|
-
// Help
|
|
189
|
-
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
|
190
|
-
console.log('Usage:');
|
|
191
|
-
console.log(' genie helper bullet-id file.md');
|
|
192
|
-
console.log(' Generate next ID for file');
|
|
193
|
-
console.log('');
|
|
194
|
-
console.log(' genie helper bullet-id file.md --count=10');
|
|
195
|
-
console.log(' Generate batch of 10 IDs');
|
|
196
|
-
console.log('');
|
|
197
|
-
console.log(' genie helper bullet-id file.md --peek');
|
|
198
|
-
console.log(' Show next ID without incrementing');
|
|
199
|
-
console.log('');
|
|
200
|
-
console.log('Examples:');
|
|
201
|
-
console.log(' $ genie helper bullet-id .genie/spells/learn.md');
|
|
202
|
-
console.log(' learn-042');
|
|
203
|
-
console.log('');
|
|
204
|
-
console.log(' $ genie helper bullet-id .genie/spells/learn.md --count=5');
|
|
205
|
-
console.log(' learn-042');
|
|
206
|
-
console.log(' learn-043');
|
|
207
|
-
console.log(' learn-044');
|
|
208
|
-
console.log(' learn-045');
|
|
209
|
-
console.log(' learn-046');
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const filePath = args[0];
|
|
214
|
-
const countArg = args.find(a => a.startsWith('--count='));
|
|
215
|
-
const peek = args.includes('--peek');
|
|
216
|
-
|
|
217
|
-
if (!filePath) {
|
|
218
|
-
console.error('Error: File path required');
|
|
219
|
-
console.error('Usage: genie helper bullet-id file.md');
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Batch generation
|
|
224
|
-
if (countArg) {
|
|
225
|
-
const count = parseInt(countArg.split('=')[1], 10);
|
|
226
|
-
if (isNaN(count) || count < 1) {
|
|
227
|
-
console.error('Error: Invalid count');
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const ids = generateBatchIds(filePath, count);
|
|
232
|
-
ids.forEach(id => console.log(id));
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Single ID generation
|
|
237
|
-
const id = generateSingleId(filePath, peek);
|
|
238
|
-
console.log(id);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
main().catch(err => {
|
|
242
|
-
console.error('ERROR:', err.message);
|
|
243
|
-
process.exit(1);
|
|
244
|
-
});
|