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,237 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Check Secrets Helper
|
|
5
|
-
*
|
|
6
|
-
* Fast, deterministic secret detection using regex patterns.
|
|
7
|
-
* No LLM needed - pure pattern matching.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* genie helper check-secrets [files...]
|
|
11
|
-
* genie helper check-secrets --staged (check git staged files)
|
|
12
|
-
*
|
|
13
|
-
* Exit codes:
|
|
14
|
-
* 0 - No secrets found
|
|
15
|
-
* 1 - Secrets detected
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const { execSync } = require('child_process');
|
|
19
|
-
const fs = require('fs');
|
|
20
|
-
const path = require('path');
|
|
21
|
-
|
|
22
|
-
// Secret patterns (regex)
|
|
23
|
-
const SECRET_PATTERNS = [
|
|
24
|
-
// API Keys
|
|
25
|
-
{ pattern: /['"]?[A-Z_]{3,}API[_-]?KEY['"]?\s*[:=]\s*['"][^'"]{20,}['"]/, name: 'API Key', severity: 'critical' },
|
|
26
|
-
{ pattern: /AKIA[0-9A-Z]{16}/, name: 'AWS Access Key', severity: 'critical' },
|
|
27
|
-
|
|
28
|
-
// Private Keys
|
|
29
|
-
{ pattern: /-----BEGIN (RSA |DSA |EC )?PRIVATE KEY-----/, name: 'Private Key', severity: 'critical' },
|
|
30
|
-
{ pattern: /-----BEGIN OPENSSH PRIVATE KEY-----/, name: 'SSH Private Key', severity: 'critical' },
|
|
31
|
-
|
|
32
|
-
// Tokens
|
|
33
|
-
{ pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/, name: 'GitHub Token', severity: 'critical' },
|
|
34
|
-
{ pattern: /glpat-[A-Za-z0-9_-]{20,}/, name: 'GitLab Token', severity: 'critical' },
|
|
35
|
-
{ pattern: /sk-[A-Za-z0-9]{20,}/, name: 'OpenAI API Key', severity: 'critical' },
|
|
36
|
-
{ pattern: /AIza[0-9A-Za-z_-]{35}/, name: 'Google API Key', severity: 'high' },
|
|
37
|
-
|
|
38
|
-
// Credentials
|
|
39
|
-
{ pattern: /['"]?password['"]?\s*[:=]\s*['"][^'"]{8,}['"]/, name: 'Password in Code', severity: 'high' },
|
|
40
|
-
{ pattern: /['"]?secret['"]?\s*[:=]\s*['"][^'"]{8,}['"]/, name: 'Secret in Code', severity: 'high' },
|
|
41
|
-
{ pattern: /['"]?token['"]?\s*[:=]\s*['"][^'"]{16,}['"]/, name: 'Token in Code', severity: 'medium' },
|
|
42
|
-
|
|
43
|
-
// Database URLs
|
|
44
|
-
{ pattern: /postgresql:\/\/[^:]+:[^@]+@/, name: 'PostgreSQL Connection String', severity: 'high' },
|
|
45
|
-
{ pattern: /mongodb(\+srv)?:\/\/[^:]+:[^@]+@/, name: 'MongoDB Connection String', severity: 'high' },
|
|
46
|
-
|
|
47
|
-
// Cryptocurrency
|
|
48
|
-
{ pattern: /0x[a-fA-F0-9]{40}/, name: 'Ethereum Address', severity: 'medium' },
|
|
49
|
-
{ pattern: /[13][a-km-zA-HJ-NP-Z1-9]{25,34}/, name: 'Bitcoin Address', severity: 'medium' },
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
// Files to always skip (even if staged)
|
|
53
|
-
const SKIP_FILES = [
|
|
54
|
-
'.genie/scripts/helpers/check-secrets.js', // This file (contains patterns)
|
|
55
|
-
'package-lock.json',
|
|
56
|
-
'pnpm-lock.yaml',
|
|
57
|
-
'yarn.lock',
|
|
58
|
-
'.git/',
|
|
59
|
-
'node_modules/',
|
|
60
|
-
'.genie/state/',
|
|
61
|
-
'.genie/backups/',
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
// Load .secretsignore file if it exists
|
|
65
|
-
function loadSecretsIgnore() {
|
|
66
|
-
const ignorePath = path.join(process.cwd(), '.genie', '.secretsignore');
|
|
67
|
-
if (!fs.existsSync(ignorePath)) {
|
|
68
|
-
return [];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const content = fs.readFileSync(ignorePath, 'utf8');
|
|
73
|
-
return content
|
|
74
|
-
.split('\n')
|
|
75
|
-
.map(line => line.trim())
|
|
76
|
-
.filter(line => line && !line.startsWith('#'))
|
|
77
|
-
.map(line => {
|
|
78
|
-
// Parse "file:line" format
|
|
79
|
-
const parts = line.split(':');
|
|
80
|
-
return {
|
|
81
|
-
file: parts[0],
|
|
82
|
-
line: parts[1] ? parseInt(parts[1]) : null
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
} catch (e) {
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function shouldSkipFile(file) {
|
|
91
|
-
return SKIP_FILES.some(skip => file.includes(skip));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function isIgnoredFinding(finding, ignoreList) {
|
|
95
|
-
return ignoreList.some(ignore => {
|
|
96
|
-
const fileMatches = finding.file === ignore.file || finding.file.endsWith(ignore.file);
|
|
97
|
-
const lineMatches = ignore.line === null || ignore.line === finding.line;
|
|
98
|
-
return fileMatches && lineMatches;
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function getStagedFiles() {
|
|
103
|
-
try {
|
|
104
|
-
const files = execSync('git diff --cached --name-only --diff-filter=ACM', {
|
|
105
|
-
encoding: 'utf8',
|
|
106
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
107
|
-
}).trim().split('\n').filter(Boolean);
|
|
108
|
-
|
|
109
|
-
return files.filter(f => !shouldSkipFile(f) && fs.existsSync(f));
|
|
110
|
-
} catch (e) {
|
|
111
|
-
return [];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function checkFile(filePath) {
|
|
116
|
-
const findings = [];
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
120
|
-
const lines = content.split('\n');
|
|
121
|
-
|
|
122
|
-
lines.forEach((line, lineNum) => {
|
|
123
|
-
SECRET_PATTERNS.forEach(({ pattern, name, severity }) => {
|
|
124
|
-
if (pattern.test(line)) {
|
|
125
|
-
findings.push({
|
|
126
|
-
file: filePath,
|
|
127
|
-
line: lineNum + 1,
|
|
128
|
-
pattern: name,
|
|
129
|
-
severity,
|
|
130
|
-
snippet: line.trim().substring(0, 80)
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
} catch (e) {
|
|
136
|
-
// Skip files that can't be read (binary, etc)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return findings;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function formatFindings(findings) {
|
|
143
|
-
if (findings.length === 0) {
|
|
144
|
-
return '✅ No secrets detected';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const critical = findings.filter(f => f.severity === 'critical');
|
|
148
|
-
const high = findings.filter(f => f.severity === 'high');
|
|
149
|
-
const medium = findings.filter(f => f.severity === 'medium');
|
|
150
|
-
|
|
151
|
-
let report = [];
|
|
152
|
-
report.push('');
|
|
153
|
-
report.push('❌ SECRETS DETECTED IN STAGED FILES');
|
|
154
|
-
report.push('━'.repeat(60));
|
|
155
|
-
report.push('');
|
|
156
|
-
|
|
157
|
-
if (critical.length > 0) {
|
|
158
|
-
report.push('🔴 CRITICAL (blocks commit):');
|
|
159
|
-
critical.forEach(f => {
|
|
160
|
-
report.push(` ${f.file}:${f.line}`);
|
|
161
|
-
report.push(` Pattern: ${f.pattern}`);
|
|
162
|
-
report.push(` Snippet: ${f.snippet}`);
|
|
163
|
-
report.push('');
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (high.length > 0) {
|
|
168
|
-
report.push('🟠 HIGH (blocks commit):');
|
|
169
|
-
high.forEach(f => {
|
|
170
|
-
report.push(` ${f.file}:${f.line}`);
|
|
171
|
-
report.push(` Pattern: ${f.pattern}`);
|
|
172
|
-
report.push('');
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (medium.length > 0) {
|
|
177
|
-
report.push('🟡 MEDIUM (warning):');
|
|
178
|
-
medium.forEach(f => {
|
|
179
|
-
report.push(` ${f.file}:${f.line} - ${f.pattern}`);
|
|
180
|
-
});
|
|
181
|
-
report.push('');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
report.push('━'.repeat(60));
|
|
185
|
-
report.push('');
|
|
186
|
-
report.push('🔧 How to fix:');
|
|
187
|
-
report.push(' 1. Remove secrets from code');
|
|
188
|
-
report.push(' 2. Use environment variables instead (.env files)');
|
|
189
|
-
report.push(' 3. Add .env* to .gitignore');
|
|
190
|
-
report.push(' 4. If false positive, add to .genie/.secretsignore');
|
|
191
|
-
report.push('');
|
|
192
|
-
|
|
193
|
-
return report.join('\n');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function main() {
|
|
197
|
-
const args = process.argv.slice(2);
|
|
198
|
-
|
|
199
|
-
let files = [];
|
|
200
|
-
|
|
201
|
-
if (args.includes('--staged') || args.length === 0) {
|
|
202
|
-
// Default: check staged files
|
|
203
|
-
files = getStagedFiles();
|
|
204
|
-
} else {
|
|
205
|
-
// Check specific files
|
|
206
|
-
files = args.filter(f => fs.existsSync(f) && !shouldSkipFile(f));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (files.length === 0) {
|
|
210
|
-
console.log('✅ No files to check');
|
|
211
|
-
process.exit(0);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Load ignore list
|
|
215
|
-
const ignoreList = loadSecretsIgnore();
|
|
216
|
-
|
|
217
|
-
let allFindings = [];
|
|
218
|
-
files.forEach(file => {
|
|
219
|
-
const findings = checkFile(file);
|
|
220
|
-
allFindings = allFindings.concat(findings);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Filter out ignored findings
|
|
224
|
-
const filteredFindings = allFindings.filter(f => !isIgnoredFinding(f, ignoreList));
|
|
225
|
-
|
|
226
|
-
console.log(formatFindings(filteredFindings));
|
|
227
|
-
|
|
228
|
-
// Block on critical or high severity
|
|
229
|
-
const blocking = filteredFindings.filter(f => f.severity === 'critical' || f.severity === 'high');
|
|
230
|
-
if (blocking.length > 0) {
|
|
231
|
-
process.exit(1);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
process.exit(0);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
main();
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Token Counter Helper
|
|
5
|
-
*
|
|
6
|
-
* Count tokens in files or text using tiktoken (cl100k_base encoding).
|
|
7
|
-
* This is the ONLY way to count tokens in the Genie framework.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* node count-tokens.js <file-path> # Output: just token count number
|
|
11
|
-
* node count-tokens.js <file-path> --json # Output: JSON with metadata
|
|
12
|
-
* echo "some text" | node count-tokens.js # Output: just token count
|
|
13
|
-
* node count-tokens.js --before=file --after=file # Compare (always JSON)
|
|
14
|
-
*
|
|
15
|
-
* Output (default):
|
|
16
|
-
* Plain number: 1234
|
|
17
|
-
*
|
|
18
|
-
* Output (--json):
|
|
19
|
-
* JSON: { tokens: N, lines: N, bytes: N, encoding: "cl100k_base" }
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
const fs = require('fs');
|
|
23
|
-
const path = require('path');
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Count tokens using tiktoken
|
|
27
|
-
*/
|
|
28
|
-
function countTokens(text) {
|
|
29
|
-
try {
|
|
30
|
-
const { getEncoding } = require('js-tiktoken');
|
|
31
|
-
const encName = process.env.TOKEN_ENCODING || 'cl100k_base';
|
|
32
|
-
const encoder = getEncoding(encName);
|
|
33
|
-
const tokens = encoder.encode(text).length;
|
|
34
|
-
try { encoder.free && encoder.free(); } catch {}
|
|
35
|
-
return { tokens, encoding: encName, method: 'tiktoken' };
|
|
36
|
-
} catch (err) {
|
|
37
|
-
// Fallback to word count approximation (should not happen if tiktoken installed)
|
|
38
|
-
console.error(`Warning: tiktoken failed, using word count fallback: ${err.message}`);
|
|
39
|
-
const approx = (text || '').trim().split(/\s+/).filter(Boolean).length;
|
|
40
|
-
return { tokens: approx, encoding: 'approx-words', method: 'fallback' };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get file stats (lines, bytes)
|
|
46
|
-
*/
|
|
47
|
-
function getStats(text) {
|
|
48
|
-
const lines = (text.match(/\n/g) || []).length + 1;
|
|
49
|
-
const bytes = Buffer.byteLength(text, 'utf8');
|
|
50
|
-
return { lines, bytes };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Count tokens in file
|
|
55
|
-
*/
|
|
56
|
-
function countFile(filePath) {
|
|
57
|
-
try {
|
|
58
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
59
|
-
const { tokens, encoding, method } = countTokens(content);
|
|
60
|
-
const { lines, bytes } = getStats(content);
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
file: path.basename(filePath),
|
|
64
|
-
path: filePath,
|
|
65
|
-
tokens,
|
|
66
|
-
lines,
|
|
67
|
-
bytes,
|
|
68
|
-
encoding,
|
|
69
|
-
method,
|
|
70
|
-
};
|
|
71
|
-
} catch (err) {
|
|
72
|
-
return {
|
|
73
|
-
error: err.message,
|
|
74
|
-
file: filePath,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Compare before/after token counts
|
|
81
|
-
*/
|
|
82
|
-
function compareFiles(beforePath, afterPath) {
|
|
83
|
-
const before = countFile(beforePath);
|
|
84
|
-
const after = countFile(afterPath);
|
|
85
|
-
|
|
86
|
-
if (before.error || after.error) {
|
|
87
|
-
return { error: 'Failed to read files' };
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const diff = after.tokens - before.tokens;
|
|
91
|
-
const percentChange = ((diff / before.tokens) * 100).toFixed(1);
|
|
92
|
-
const saved = diff < 0;
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
before: {
|
|
96
|
-
file: before.file,
|
|
97
|
-
tokens: before.tokens,
|
|
98
|
-
lines: before.lines,
|
|
99
|
-
bytes: before.bytes,
|
|
100
|
-
},
|
|
101
|
-
after: {
|
|
102
|
-
file: after.file,
|
|
103
|
-
tokens: after.tokens,
|
|
104
|
-
lines: after.lines,
|
|
105
|
-
bytes: after.bytes,
|
|
106
|
-
},
|
|
107
|
-
diff: {
|
|
108
|
-
tokens: diff,
|
|
109
|
-
percent: percentChange,
|
|
110
|
-
saved: saved,
|
|
111
|
-
message: saved
|
|
112
|
-
? `Saved ${Math.abs(diff)} tokens (${Math.abs(percentChange)}% reduction)`
|
|
113
|
-
: `Added ${diff} tokens (${percentChange}% increase)`,
|
|
114
|
-
},
|
|
115
|
-
encoding: before.encoding,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Main
|
|
121
|
-
*/
|
|
122
|
-
function main() {
|
|
123
|
-
const args = process.argv.slice(2);
|
|
124
|
-
const jsonMode = args.includes('--json');
|
|
125
|
-
const fileArgs = args.filter(a => !a.startsWith('--'));
|
|
126
|
-
|
|
127
|
-
// Check for comparison mode (--before=file --after=file)
|
|
128
|
-
const beforeArg = args.find(a => a.startsWith('--before='));
|
|
129
|
-
const afterArg = args.find(a => a.startsWith('--after='));
|
|
130
|
-
|
|
131
|
-
if (beforeArg && afterArg) {
|
|
132
|
-
const beforePath = beforeArg.split('=')[1];
|
|
133
|
-
const afterPath = afterArg.split('=')[1];
|
|
134
|
-
const result = compareFiles(beforePath, afterPath);
|
|
135
|
-
console.log(JSON.stringify(result, null, 2));
|
|
136
|
-
process.exit(result.error ? 1 : 0);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Single file mode
|
|
140
|
-
if (fileArgs.length > 0) {
|
|
141
|
-
const filePath = fileArgs[0];
|
|
142
|
-
if (!fs.existsSync(filePath)) {
|
|
143
|
-
console.error(jsonMode
|
|
144
|
-
? JSON.stringify({ error: `File not found: ${filePath}` })
|
|
145
|
-
: `Error: File not found: ${filePath}`);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
}
|
|
148
|
-
const result = countFile(filePath);
|
|
149
|
-
if (result.error) {
|
|
150
|
-
console.error(jsonMode ? JSON.stringify(result) : `Error: ${result.error}`);
|
|
151
|
-
process.exit(1);
|
|
152
|
-
}
|
|
153
|
-
console.log(jsonMode ? JSON.stringify(result, null, 2) : result.tokens.toString());
|
|
154
|
-
process.exit(0);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Stdin mode
|
|
158
|
-
if (!process.stdin.isTTY) {
|
|
159
|
-
let input = '';
|
|
160
|
-
process.stdin.setEncoding('utf-8');
|
|
161
|
-
process.stdin.on('data', chunk => input += chunk);
|
|
162
|
-
process.stdin.on('end', () => {
|
|
163
|
-
const { tokens, encoding, method } = countTokens(input);
|
|
164
|
-
const { lines, bytes } = getStats(input);
|
|
165
|
-
if (jsonMode) {
|
|
166
|
-
console.log(JSON.stringify({
|
|
167
|
-
tokens,
|
|
168
|
-
lines,
|
|
169
|
-
bytes,
|
|
170
|
-
encoding,
|
|
171
|
-
method,
|
|
172
|
-
}, null, 2));
|
|
173
|
-
} else {
|
|
174
|
-
console.log(tokens.toString());
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// No input, show usage
|
|
181
|
-
console.error(`
|
|
182
|
-
Usage:
|
|
183
|
-
node count-tokens.js <file-path> # Output: just token count (number)
|
|
184
|
-
node count-tokens.js <file-path> --json # Output: JSON with metadata
|
|
185
|
-
echo "text" | node count-tokens.js # Output: just token count
|
|
186
|
-
node count-tokens.js --before=old.md --after=new.md # Compare files (always JSON)
|
|
187
|
-
|
|
188
|
-
Output (default): Plain number (e.g., "1234")
|
|
189
|
-
Output (--json): JSON with token count, lines, bytes, encoding
|
|
190
|
-
|
|
191
|
-
Examples:
|
|
192
|
-
node count-tokens.js README.md # 1234
|
|
193
|
-
node count-tokens.js README.md --json # { "tokens": 1234, ... }
|
|
194
|
-
node count-tokens.js --before=before.md --after=after.md
|
|
195
|
-
cat myfile.md | node count-tokens.js
|
|
196
|
-
`);
|
|
197
|
-
process.exit(1);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
main();
|