@codacy/gate-cli 0.2.0 → 0.3.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.
package/bin/gate.js CHANGED
@@ -12093,8 +12093,138 @@ async function runReview(opts, globals) {
12093
12093
  process.exit(0);
12094
12094
  }
12095
12095
 
12096
+ // src/commands/init.ts
12097
+ var import_node_fs9 = require("node:fs");
12098
+ var import_promises8 = require("node:fs/promises");
12099
+ var import_node_path6 = require("node:path");
12100
+ var import_node_child_process5 = require("node:child_process");
12101
+ function resolveDataDir() {
12102
+ const candidates = [
12103
+ (0, import_node_path6.join)(__dirname, "..", "data"),
12104
+ // installed: node_modules/@codacy/gate-cli/data
12105
+ (0, import_node_path6.join)(__dirname, "..", "..", "data"),
12106
+ // edge case: nested resolution
12107
+ (0, import_node_path6.join)(process.cwd(), "cli", "data")
12108
+ // local dev: running from repo root
12109
+ ];
12110
+ for (const candidate of candidates) {
12111
+ if ((0, import_node_fs9.existsSync)((0, import_node_path6.join)(candidate, "skills"))) {
12112
+ return candidate;
12113
+ }
12114
+ }
12115
+ throw new Error(
12116
+ "Could not find GATE.md skill data. Reinstall: npm install -g @codacy/gate-cli"
12117
+ );
12118
+ }
12119
+ async function copyDir(src, dest) {
12120
+ await (0, import_promises8.mkdir)(dest, { recursive: true });
12121
+ await (0, import_promises8.cp)(src, dest, { recursive: true, force: true });
12122
+ }
12123
+ function registerInitCommand(program2) {
12124
+ program2.command("init").description("Initialize GATE.md in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
12125
+ const force = opts.force ?? false;
12126
+ const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
12127
+ const isProject = projectMarkers.some((m) => (0, import_node_fs9.existsSync)(m));
12128
+ if (!isProject) {
12129
+ printError("No project detected in the current directory.");
12130
+ printInfo('Run "gate init" from your project root.');
12131
+ process.exit(1);
12132
+ }
12133
+ console.log("");
12134
+ printInfo("Initializing GATE.md in this project...");
12135
+ console.log("");
12136
+ printInfo("Checking prerequisites...");
12137
+ const nodeVersion = process.version;
12138
+ const nodeMajor = parseInt(nodeVersion.slice(1), 10);
12139
+ if (nodeMajor < 20) {
12140
+ printError(`Node.js 20+ required (found ${nodeVersion}). Update from https://nodejs.org`);
12141
+ process.exit(1);
12142
+ }
12143
+ printInfo(` Node.js ${nodeVersion} \u2713`);
12144
+ try {
12145
+ const gitVersion = (0, import_node_child_process5.execSync)("git --version", { encoding: "utf-8" }).trim();
12146
+ printInfo(` ${gitVersion} \u2713`);
12147
+ } catch {
12148
+ printError("git is required but not installed. Install from https://git-scm.com");
12149
+ process.exit(1);
12150
+ }
12151
+ try {
12152
+ (0, import_node_child_process5.execSync)("which claude", { encoding: "utf-8" });
12153
+ printInfo(" Claude Code \u2713");
12154
+ } catch {
12155
+ printWarn(" Claude Code not found \u2014 hooks will be configured but need Claude Code to run.");
12156
+ }
12157
+ try {
12158
+ (0, import_node_child_process5.execSync)("which codacy-analysis", { encoding: "utf-8" });
12159
+ printInfo(" @codacy/analysis-cli \u2713");
12160
+ } catch {
12161
+ printWarn(" @codacy/analysis-cli not found \u2014 static analysis will be unavailable.");
12162
+ printWarn(" Install: npm install -g @codacy/analysis-cli");
12163
+ }
12164
+ console.log("");
12165
+ printInfo("Installing skills...");
12166
+ const dataDir = resolveDataDir();
12167
+ const skillsSource = (0, import_node_path6.join)(dataDir, "skills");
12168
+ const skillsDest = ".claude/skills";
12169
+ const skills = ["gate-setup", "gate-analyze", "gate-status", "gate-feedback"];
12170
+ let skillsInstalled = 0;
12171
+ for (const skill of skills) {
12172
+ const src = (0, import_node_path6.join)(skillsSource, skill);
12173
+ const dest = (0, import_node_path6.join)(skillsDest, skill);
12174
+ if (!(0, import_node_fs9.existsSync)(src)) {
12175
+ printWarn(` Skill data not found: ${skill}`);
12176
+ continue;
12177
+ }
12178
+ if ((0, import_node_fs9.existsSync)(dest) && !force) {
12179
+ const srcSkill = (0, import_node_path6.join)(src, "SKILL.md");
12180
+ const destSkill = (0, import_node_path6.join)(dest, "SKILL.md");
12181
+ if ((0, import_node_fs9.existsSync)(destSkill)) {
12182
+ try {
12183
+ const srcContent = await (0, import_promises8.readFile)(srcSkill, "utf-8");
12184
+ const destContent = await (0, import_promises8.readFile)(destSkill, "utf-8");
12185
+ if (srcContent === destContent) {
12186
+ skillsInstalled++;
12187
+ continue;
12188
+ }
12189
+ } catch {
12190
+ }
12191
+ }
12192
+ }
12193
+ await copyDir(src, dest);
12194
+ skillsInstalled++;
12195
+ }
12196
+ printInfo(` ${skillsInstalled}/${skills.length} skills installed to .claude/skills/ \u2713`);
12197
+ printInfo("Wiring Claude Code hooks...");
12198
+ const settings = await readSettings();
12199
+ const hookResult = installGateHooks(settings, force);
12200
+ if (hookResult.ok) {
12201
+ await writeSettings(hookResult.data);
12202
+ printInfo(" Stop hook: gate analyze \u2713");
12203
+ printInfo(" Intent hook: gate intent capture \u2713");
12204
+ } else {
12205
+ printWarn(` ${hookResult.error}`);
12206
+ printInfo(' Run "gate hooks install --force" to overwrite.');
12207
+ }
12208
+ await (0, import_promises8.mkdir)(GATE_DIR, { recursive: true });
12209
+ const globalGateDir = (0, import_node_path6.join)(process.env.HOME ?? "", ".gate");
12210
+ await (0, import_promises8.mkdir)(globalGateDir, { recursive: true });
12211
+ console.log("");
12212
+ printInfo("GATE.md initialized!");
12213
+ console.log("");
12214
+ console.log(" Installed:");
12215
+ console.log(" .claude/skills/gate-setup/ \u2014 project configuration");
12216
+ console.log(" .claude/skills/gate-analyze/ \u2014 on-demand analysis");
12217
+ console.log(" .claude/skills/gate-status/ \u2014 project health");
12218
+ console.log(" .claude/skills/gate-feedback/ \u2014 beta feedback");
12219
+ console.log(" .claude/settings.json \u2014 hooks (gate analyze + intent capture)");
12220
+ console.log("");
12221
+ console.log(" Next step: open this project in Claude Code and run /gate-setup");
12222
+ console.log("");
12223
+ });
12224
+ }
12225
+
12096
12226
  // src/cli.ts
12097
- program.name("gate").description("CLI for GATE.md quality gate service").version("0.1.0").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
12227
+ program.name("gate").description("CLI for GATE.md quality gate service").version("0.3.0").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
12098
12228
  registerAuthCommands(program);
12099
12229
  registerHooksCommands(program);
12100
12230
  registerIntentCommands(program);
@@ -12104,4 +12234,5 @@ registerStatusCommand(program);
12104
12234
  registerFeedbackCommand(program);
12105
12235
  registerAnalyzeCommand(program);
12106
12236
  registerReviewCommand(program);
12237
+ registerInitCommand(program);
12107
12238
  program.parse();
@@ -0,0 +1,214 @@
1
+ # /gate-analyze — Run GATE.md analysis on demand
2
+
3
+ You are running an on-demand GATE.md analysis. This is like a "second opinion" — the user (or you) can invoke it at any point to get a quality and security review with rich context.
4
+
5
+ **Usage:**
6
+ - `/gate-analyze` — Curate files, write intent, select specs autonomously (deep review)
7
+ - `/gate-analyze src/api/routes.ts src/db.ts` — Analyze specific files (quick check)
8
+ - `/gate-analyze src/api/` — Analyze a directory and related files
9
+ - `/gate-analyze --full` — Sample the full codebase (20 most recently modified files)
10
+ - `/gate-analyze --intent "Implementing OAuth2 PKCE flow per spec/AUTH.md"` — User provides intent
11
+
12
+ ---
13
+
14
+ ## Step 1: Check configuration
15
+
16
+ 1. Verify `.gate/standard.yaml` exists. If not: "Run `/gate-setup` first."
17
+ 2. Verify `gate` CLI is available: `which gate`. If not: "Re-run the GATE.md installer: `curl -fsSL https://raw.githubusercontent.com/codacy/gatemd/main/install.sh | bash`"
18
+ 3. Run `gate auth verify` to check token is valid. If it fails: "GATE.md not configured. Run `/gate-setup` first."
19
+
20
+ ---
21
+
22
+ ## Step 2: Determine files to analyze
23
+
24
+ ### Quick mode (specific files or `--full`)
25
+
26
+ **Specific files** (paths or directories provided):
27
+ - Use the provided file paths directly. If a directory is given, include all analyzable files under it.
28
+ - Verify each file exists.
29
+
30
+ **`--full` flag** (full codebase sample):
31
+ ```bash
32
+ FILES=$(git ls-files | grep -E '\.(ts|tsx|js|jsx|mjs|cjs|py|go|java|kt|rb|rs|c|cpp|h|hpp|cs|php)$')
33
+ ```
34
+ If more than 20 files, select the 20 most recently modified:
35
+ ```bash
36
+ echo "$FILES" | xargs ls -t | head -20
37
+ ```
38
+
39
+ In quick mode, skip Steps 3 and 4 — go straight to Step 5.
40
+
41
+ ### Deep mode (no arguments, or directory hints)
42
+
43
+ When no specific files are given, curate a comprehensive review scope:
44
+
45
+ #### 2a. Start with changed files
46
+
47
+ ```bash
48
+ CHANGED=$(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null; git ls-files --others --exclude-standard 2>/dev/null)
49
+ CHANGED_CODE=$(echo "$CHANGED" | sort -u | grep -E '\.(ts|tsx|js|jsx|mjs|cjs|py|go|java|kt|rb|rs|c|cpp|h|hpp|cs|php)$')
50
+ ```
51
+
52
+ Also check if the agent just committed (clean tree but recent HEAD):
53
+ ```bash
54
+ # If working tree is clean, check what the last commit changed
55
+ git diff --name-only HEAD~1..HEAD 2>/dev/null
56
+ ```
57
+
58
+ If the user provided directory hints (e.g., `/gate-analyze src/api/`), also include all files under those directories.
59
+
60
+ #### 2b. Add related files
61
+
62
+ For each changed file, identify and add:
63
+
64
+ 1. **Direct dependencies** — files that the changed file imports. Read the import/require statements and resolve the paths.
65
+ 2. **Reverse dependencies** — files that import the changed file. Grep for the module name across the codebase.
66
+ 3. **Type/interface files** — shared type definitions, interfaces, or schemas referenced by the changes.
67
+ 4. **Test files** — corresponding test files for changed modules (e.g., `foo.test.ts` for `foo.ts`, `test_foo.py` for `foo.py`).
68
+
69
+ #### 2c. Prioritize and cap
70
+
71
+ Rank files by relevance:
72
+ 1. Changed files (always included first)
73
+ 2. Direct dependencies that define interfaces/types being used
74
+ 3. Test files for changed code
75
+ 4. Reverse dependencies (consumers that might break)
76
+
77
+ **Cap at 20 files total.** If you need to cut, drop reverse dependencies first, then tests.
78
+
79
+ #### 2d. Track changed vs context
80
+
81
+ Keep two lists:
82
+ - **`changed_files`** — the files that were actually modified (git dirty or recently committed)
83
+ - **`all_files`** — all files to include in the analysis (changed + context)
84
+
85
+ If no analyzable files found: "No analyzable files found."
86
+
87
+ ---
88
+
89
+ ## Step 3: Write the intent description
90
+
91
+ Synthesize the conversation context into a clear intent description. This is NOT the raw user prompt — it's your understanding of what the work is trying to achieve.
92
+
93
+ **Template:**
94
+
95
+ ```
96
+ I am [adding/modifying/fixing/refactoring] [feature/component name].
97
+
98
+ Goal: [What the user asked for, or the problem being solved.]
99
+
100
+ Approach: [Key architectural decisions. What patterns are being used?]
101
+
102
+ Trade-offs: [Anything you chose deliberately that could be questioned.]
103
+
104
+ Review focus: [Specific concerns you want the reviewer to evaluate.]
105
+ ```
106
+
107
+ **Guidelines:**
108
+ - Cap at 2000 characters
109
+ - Be specific — "adding JWT auth with RS256 to /api/users" not "adding authentication"
110
+ - Include trade-offs and areas of uncertainty — the reviewer will focus there
111
+ - If the user provided `--intent`, use it as the base and augment with your understanding
112
+ - Skip this step entirely in quick mode (specific files or --full)
113
+
114
+ ---
115
+
116
+ ## Step 4: Select relevant specs
117
+
118
+ Identify spec/documentation files that provide context:
119
+
120
+ - Specs referenced in the user's request
121
+ - Specs that define interfaces or APIs being implemented
122
+ - Architecture docs relevant to the area being changed
123
+
124
+ **Read each spec file and prepare for inclusion.** Limits: max 10 files, 10KB per file, 30KB total.
125
+
126
+ Common spec locations to check:
127
+ - `spec/*.md`, `docs/*.md`
128
+ - `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`
129
+
130
+ If no specs are relevant, skip this step.
131
+
132
+ ---
133
+
134
+ ## Step 5: Run the analysis
135
+
136
+ Use the `gate review` command with all the context you gathered:
137
+
138
+ ```bash
139
+ gate review \
140
+ --files "src/auth/pkce.ts,src/auth/callback.ts,src/auth/types.ts,src/middleware/auth.ts" \
141
+ --changed "src/auth/pkce.ts,src/auth/callback.ts" \
142
+ --intent "I am adding OAuth2 PKCE authentication flow..." \
143
+ --specs "spec/AUTH.md,CLAUDE.md"
144
+ ```
145
+
146
+ **Arguments:**
147
+ - `--files` (required): Comma-separated list of ALL files to include (changed + context)
148
+ - `--changed` (optional): Comma-separated list of actually-modified files (subset of --files). If omitted, all files are treated as changed.
149
+ - `--intent` (optional): Your synthesized intent description. Quote it.
150
+ - `--specs` (optional): Comma-separated list of spec file paths to include.
151
+
152
+ The CLI handles static analysis, file reading with size limits, payload construction, and the API call.
153
+
154
+ ---
155
+
156
+ ## Step 6: Display results
157
+
158
+ Parse the JSON response and format clearly:
159
+
160
+ ```
161
+ === GATE.md Analysis ===
162
+ Gate Decision: WARN
163
+ Quality: 7.5/10 | Security: 8.0/10 | Overall: 7.8/10
164
+ Trend: stable
165
+
166
+ --- Assessment ---
167
+ [narrative from assessment.narrative]
168
+
169
+ --- Findings (2) ---
170
+
171
+ [HIGH] Service Role Client for Non-Admin Operations
172
+ File: supabase/functions/webhook/index.ts:25
173
+ Pattern: access-control-checks (CWE-639)
174
+ Fix: Limit SELECT fields to only what's needed for the notification.
175
+
176
+ [MEDIUM] File Complexity Exceeds Threshold
177
+ File: supabase/functions/webhook/index.ts:1
178
+ Pattern: comprehensibility
179
+ Fix: Refactor into separate handler files per event type.
180
+
181
+ --- Intent Alignment ---
182
+ Score: 9/10 (aligned)
183
+ Goal: "Add webhook handlers for Stripe events"
184
+ Implementation matches intent. No gaps detected.
185
+
186
+ --- Quality Dimensions ---
187
+ Comprehensibility: 6.5/10 — webhook file is too large
188
+ Modularity: 7.0/10 — good separation except webhook handler
189
+ Type Safety: 9.0/10 — strict TypeScript throughout
190
+ Test Adequacy: 5.0/10 — missing webhook handler tests
191
+
192
+ --- Pending Items ---
193
+ 1. [HIGH] Add tests for webhook event handlers
194
+ 2. [MEDIUM] Refactor webhook into handler modules
195
+
196
+ View full report: https://gatemd.lovable.app/runs/run-20260327-...?token=gateview_...
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Step 7: Offer to fix
202
+
203
+ - **If FAIL or findings exist**: "The analysis found N issues. Would you like me to fix them?" If yes, apply fixes from findings, then re-run (iteration 2 max). If iteration 2 still fails, report remaining issues for human review.
204
+ - **If WARN**: "Non-blocking issues found. Would you like me to address them?"
205
+ - **If PASS**: "Code meets the Standard. No issues found."
206
+
207
+ ---
208
+
209
+ ## Important notes
210
+
211
+ - This does NOT replace the automatic stop hook. The hook still fires on every agent stop.
212
+ - Runs are tagged with `trigger: "review"` in the database.
213
+ - Size limits: 20 files max, 50KB per file, 200KB total code, 2000 char intent, 30KB specs.
214
+ - If the service is unreachable, static analysis still runs locally.
@@ -0,0 +1,12 @@
1
+ # /gate-feedback — Send feedback to the GATE.md team
2
+
3
+ If the user provided a message (e.g., `/gate-feedback the analysis is too slow`), use their **exact words** as the message. Do NOT rephrase, expand, add context, or editorialize. Send exactly what they typed, nothing more.
4
+
5
+ If they just typed `/gate-feedback` with no message, ask: "What feedback would you like to share?"
6
+
7
+ ```bash
8
+ gate feedback "<their exact message>"
9
+ ```
10
+
11
+ On success: "Thanks, feedback sent!"
12
+ On error: "Couldn't send feedback right now. Your message: [repeat it so it's not lost]."