@codacy/gate-cli 0.3.0 → 0.4.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/README.md +31 -15
- package/bin/gate.js +80 -51
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,46 @@
|
|
|
1
1
|
# @codacy/gate-cli
|
|
2
2
|
|
|
3
|
-
CLI for [GATE.md](https://
|
|
3
|
+
CLI for [GATE.md](https://gatemd.lovable.app) — the quality gate for AI-generated code.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g @codacy/gate-cli
|
|
9
|
+
cd your-project
|
|
10
|
+
gate init
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Then open the project in Claude Code and run `/gate-setup`.
|
|
14
|
+
|
|
15
|
+
### Permission denied?
|
|
16
|
+
|
|
17
|
+
If `npm install -g` fails with `EACCES`, your npm global directory needs fixing. Pick one:
|
|
18
|
+
|
|
19
|
+
**Option A — Fix npm prefix (recommended, one-time):**
|
|
20
|
+
```bash
|
|
21
|
+
mkdir -p ~/.npm-global
|
|
22
|
+
npm config set prefix ~/.npm-global
|
|
23
|
+
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.zshrc # or ~/.bashrc
|
|
24
|
+
source ~/.zshrc
|
|
25
|
+
npm install -g @codacy/gate-cli
|
|
26
|
+
```
|
|
12
27
|
|
|
13
|
-
|
|
28
|
+
**Option B — Use npx (no global install):**
|
|
29
|
+
```bash
|
|
30
|
+
npx @codacy/gate-cli init
|
|
31
|
+
npx @codacy/gate-cli hooks install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Option C — Use sudo (not recommended):**
|
|
35
|
+
```bash
|
|
36
|
+
sudo npm install -g @codacy/gate-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick reference
|
|
14
40
|
|
|
15
41
|
| Command | Description |
|
|
16
42
|
|---------|-------------|
|
|
43
|
+
| `gate init` | Initialize GATE.md in current project (skills + hooks) |
|
|
17
44
|
| `gate analyze` | Run analysis on changed files (stop hook) |
|
|
18
45
|
| `gate review --files <paths>` | On-demand analysis (advisory) |
|
|
19
46
|
| `gate auth register` | Register a project |
|
|
@@ -23,7 +50,6 @@ Requires Node.js 20+.
|
|
|
23
50
|
| `gate config push` | Upload analysis config |
|
|
24
51
|
| `gate status` | Show project quality status |
|
|
25
52
|
| `gate feedback <msg>` | Send feedback |
|
|
26
|
-
| `gate intent capture` | Capture user intent (hook) |
|
|
27
53
|
|
|
28
54
|
## Global flags
|
|
29
55
|
|
|
@@ -43,14 +69,4 @@ GATE.md intercepts AI coding agent output, runs static analysis + independent Ge
|
|
|
43
69
|
Agent writes code → gate analyze → codacy-analysis + Gemini → PASS/FAIL
|
|
44
70
|
```
|
|
45
71
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
# Install
|
|
50
|
-
npm install -g @codacy/gate-cli @codacy/analysis-cli
|
|
51
|
-
|
|
52
|
-
# Wire Claude Code hooks
|
|
53
|
-
gate hooks install
|
|
54
|
-
|
|
55
|
-
# Then run /gate-setup in Claude Code to register + configure
|
|
56
|
-
```
|
|
72
|
+
Requires Node.js 20+.
|
package/bin/gate.js
CHANGED
|
@@ -10326,14 +10326,27 @@ var {
|
|
|
10326
10326
|
|
|
10327
10327
|
// src/commands/auth.ts
|
|
10328
10328
|
var import_promises3 = require("node:fs/promises");
|
|
10329
|
-
var
|
|
10330
|
-
var
|
|
10329
|
+
var import_node_child_process3 = require("node:child_process");
|
|
10330
|
+
var import_node_path2 = require("node:path");
|
|
10331
10331
|
|
|
10332
10332
|
// src/lib/auth.ts
|
|
10333
10333
|
var import_promises = require("node:fs/promises");
|
|
10334
|
-
var
|
|
10334
|
+
var import_node_child_process2 = require("node:child_process");
|
|
10335
10335
|
|
|
10336
10336
|
// src/constants.ts
|
|
10337
|
+
var import_node_child_process = require("node:child_process");
|
|
10338
|
+
var import_node_path = require("node:path");
|
|
10339
|
+
var _repoRoot = null;
|
|
10340
|
+
function repoRoot() {
|
|
10341
|
+
if (_repoRoot === null) {
|
|
10342
|
+
try {
|
|
10343
|
+
_repoRoot = (0, import_node_child_process.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
10344
|
+
} catch {
|
|
10345
|
+
_repoRoot = process.cwd();
|
|
10346
|
+
}
|
|
10347
|
+
}
|
|
10348
|
+
return _repoRoot;
|
|
10349
|
+
}
|
|
10337
10350
|
var GATE_DIR = ".gate";
|
|
10338
10351
|
var CREDENTIALS_FILE = `${GATE_DIR}/credentials`;
|
|
10339
10352
|
var GLOBAL_CREDENTIALS_FILE = `${process.env.HOME}/.gate/credentials`;
|
|
@@ -10346,6 +10359,9 @@ var GATE_MD_FILE = "GATE.md";
|
|
|
10346
10359
|
var CLAUDE_SETTINGS_FILE = ".claude/settings.json";
|
|
10347
10360
|
var STANDARD_FILE = `${GATE_DIR}/standard.yaml`;
|
|
10348
10361
|
var CODACY_CONFIG_FILE = ".codacy/codacy.config.json";
|
|
10362
|
+
function projectPath(relativePath) {
|
|
10363
|
+
return (0, import_node_path.join)(repoRoot(), relativePath);
|
|
10364
|
+
}
|
|
10349
10365
|
var MAX_DELTA_BYTES = 204800;
|
|
10350
10366
|
var MAX_FILES = 20;
|
|
10351
10367
|
var MAX_FILE_BYTES = 51200;
|
|
@@ -10460,7 +10476,7 @@ async function resolveToken(flagToken) {
|
|
|
10460
10476
|
return { ok: true, data: { token: envToken, source: "env" } };
|
|
10461
10477
|
}
|
|
10462
10478
|
try {
|
|
10463
|
-
const content = await (0, import_promises.readFile)(CREDENTIALS_FILE, "utf-8");
|
|
10479
|
+
const content = await (0, import_promises.readFile)(projectPath(CREDENTIALS_FILE), "utf-8");
|
|
10464
10480
|
const match = content.match(/token:\s*(gate_[a-f0-9]+)/);
|
|
10465
10481
|
if (match) {
|
|
10466
10482
|
return { ok: true, data: { token: match[1], source: "local" } };
|
|
@@ -10472,7 +10488,7 @@ async function resolveToken(flagToken) {
|
|
|
10472
10488
|
const content = await (0, import_promises.readFile)(globalCredentials, "utf-8");
|
|
10473
10489
|
let remote = "";
|
|
10474
10490
|
try {
|
|
10475
|
-
remote = (0,
|
|
10491
|
+
remote = (0, import_node_child_process2.execSync)("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
10476
10492
|
} catch {
|
|
10477
10493
|
}
|
|
10478
10494
|
if (remote) {
|
|
@@ -10504,7 +10520,7 @@ async function resolveServiceUrl(flagUrl) {
|
|
|
10504
10520
|
return { ok: true, data: envUrl };
|
|
10505
10521
|
}
|
|
10506
10522
|
try {
|
|
10507
|
-
const creds = await (0, import_promises2.readFile)(CREDENTIALS_FILE, "utf-8");
|
|
10523
|
+
const creds = await (0, import_promises2.readFile)(projectPath(CREDENTIALS_FILE), "utf-8");
|
|
10508
10524
|
const match = creds.match(/service_url:\s*(https?:\/\/[^\s]+)/);
|
|
10509
10525
|
if (match) {
|
|
10510
10526
|
return { ok: true, data: match[1] };
|
|
@@ -10512,7 +10528,7 @@ async function resolveServiceUrl(flagUrl) {
|
|
|
10512
10528
|
} catch {
|
|
10513
10529
|
}
|
|
10514
10530
|
try {
|
|
10515
|
-
const content = await (0, import_promises2.readFile)(GATE_MD_FILE, "utf-8");
|
|
10531
|
+
const content = await (0, import_promises2.readFile)(projectPath(GATE_MD_FILE), "utf-8");
|
|
10516
10532
|
const boldMatch = content.match(/\*\*url\*\*/i);
|
|
10517
10533
|
if (boldMatch) {
|
|
10518
10534
|
const lineMatch = content.split("\n").find((l) => /\*\*url\*\*/i.test(l));
|
|
@@ -10621,7 +10637,7 @@ function registerAuthCommands(program2) {
|
|
|
10621
10637
|
let remote = opts.remote;
|
|
10622
10638
|
if (!remote) {
|
|
10623
10639
|
try {
|
|
10624
|
-
remote = (0,
|
|
10640
|
+
remote = (0, import_node_child_process3.execSync)("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
10625
10641
|
} catch {
|
|
10626
10642
|
printError("No git remote found. Use --remote to specify one.");
|
|
10627
10643
|
process.exit(1);
|
|
@@ -10644,7 +10660,7 @@ function registerAuthCommands(program2) {
|
|
|
10644
10660
|
service_url: ${service_url}
|
|
10645
10661
|
`);
|
|
10646
10662
|
try {
|
|
10647
|
-
await (0, import_promises3.mkdir)((0,
|
|
10663
|
+
await (0, import_promises3.mkdir)((0, import_node_path2.dirname)(GLOBAL_CREDENTIALS_FILE), { recursive: true });
|
|
10648
10664
|
await (0, import_promises3.appendFile)(GLOBAL_CREDENTIALS_FILE, `${remote} token: ${token}
|
|
10649
10665
|
`);
|
|
10650
10666
|
} catch {
|
|
@@ -10683,7 +10699,7 @@ service_url: ${service_url}
|
|
|
10683
10699
|
let remote = opts.remote;
|
|
10684
10700
|
if (!remote) {
|
|
10685
10701
|
try {
|
|
10686
|
-
remote = (0,
|
|
10702
|
+
remote = (0, import_node_child_process3.execSync)("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
10687
10703
|
} catch {
|
|
10688
10704
|
printError("No git remote found. Use --remote to specify one.");
|
|
10689
10705
|
process.exit(1);
|
|
@@ -10711,7 +10727,7 @@ service_url: ${service_url}
|
|
|
10711
10727
|
|
|
10712
10728
|
// src/lib/hooks.ts
|
|
10713
10729
|
var import_promises4 = require("node:fs/promises");
|
|
10714
|
-
var
|
|
10730
|
+
var import_node_path3 = require("node:path");
|
|
10715
10731
|
var GATE_STOP_HOOK = {
|
|
10716
10732
|
type: "command",
|
|
10717
10733
|
command: "gate analyze",
|
|
@@ -10734,7 +10750,7 @@ async function readSettings() {
|
|
|
10734
10750
|
}
|
|
10735
10751
|
}
|
|
10736
10752
|
async function writeSettings(settings) {
|
|
10737
|
-
await (0, import_promises4.mkdir)((0,
|
|
10753
|
+
await (0, import_promises4.mkdir)((0, import_node_path3.dirname)(CLAUDE_SETTINGS_FILE), { recursive: true });
|
|
10738
10754
|
await (0, import_promises4.writeFile)(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2) + "\n");
|
|
10739
10755
|
}
|
|
10740
10756
|
function checkGateHooks(settings) {
|
|
@@ -11208,9 +11224,9 @@ function registerFeedbackCommand(program2) {
|
|
|
11208
11224
|
}
|
|
11209
11225
|
|
|
11210
11226
|
// src/lib/git.ts
|
|
11211
|
-
var
|
|
11227
|
+
var import_node_child_process4 = require("node:child_process");
|
|
11212
11228
|
var import_node_fs2 = require("node:fs");
|
|
11213
|
-
var
|
|
11229
|
+
var import_node_path4 = require("node:path");
|
|
11214
11230
|
function resolveFile(relpath) {
|
|
11215
11231
|
if ((0, import_node_fs2.existsSync)(relpath)) return relpath;
|
|
11216
11232
|
if ((0, import_node_fs2.existsSync)(".claude/worktrees")) {
|
|
@@ -11218,7 +11234,7 @@ function resolveFile(relpath) {
|
|
|
11218
11234
|
const entries = (0, import_node_fs2.readdirSync)(".claude/worktrees", { withFileTypes: true });
|
|
11219
11235
|
for (const entry of entries) {
|
|
11220
11236
|
if (!entry.isDirectory()) continue;
|
|
11221
|
-
const candidate = (0,
|
|
11237
|
+
const candidate = (0, import_node_path4.join)(".claude/worktrees", entry.name, relpath);
|
|
11222
11238
|
if ((0, import_node_fs2.existsSync)(candidate)) return candidate;
|
|
11223
11239
|
}
|
|
11224
11240
|
} catch {
|
|
@@ -11228,7 +11244,7 @@ function resolveFile(relpath) {
|
|
|
11228
11244
|
}
|
|
11229
11245
|
function execGit(cmd) {
|
|
11230
11246
|
try {
|
|
11231
|
-
return (0,
|
|
11247
|
+
return (0, import_node_child_process4.execSync)(cmd, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
11232
11248
|
} catch {
|
|
11233
11249
|
return "";
|
|
11234
11250
|
}
|
|
@@ -11271,7 +11287,7 @@ function getWorktreeFiles() {
|
|
|
11271
11287
|
const entries = (0, import_node_fs2.readdirSync)(worktreeDir, { withFileTypes: true });
|
|
11272
11288
|
for (const entry of entries) {
|
|
11273
11289
|
if (!entry.isDirectory()) continue;
|
|
11274
|
-
const wtDir = (0,
|
|
11290
|
+
const wtDir = (0, import_node_path4.join)(worktreeDir, entry.name);
|
|
11275
11291
|
scanDir(wtDir, wtDir, fiveMinAgo, result);
|
|
11276
11292
|
}
|
|
11277
11293
|
} catch {
|
|
@@ -11282,12 +11298,12 @@ function scanDir(baseDir, dir, minMtime, result) {
|
|
|
11282
11298
|
try {
|
|
11283
11299
|
const entries = (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
11284
11300
|
for (const entry of entries) {
|
|
11285
|
-
const fullPath = (0,
|
|
11301
|
+
const fullPath = (0, import_node_path4.join)(dir, entry.name);
|
|
11286
11302
|
if (entry.isDirectory()) {
|
|
11287
11303
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
11288
11304
|
scanDir(baseDir, fullPath, minMtime, result);
|
|
11289
11305
|
} else if (entry.isFile()) {
|
|
11290
|
-
const ext = (0,
|
|
11306
|
+
const ext = (0, import_node_path4.extname)(entry.name).slice(1);
|
|
11291
11307
|
if (!ANALYZABLE_EXTENSIONS.has(ext)) continue;
|
|
11292
11308
|
try {
|
|
11293
11309
|
const stat = (0, import_node_fs2.statSync)(fullPath);
|
|
@@ -11304,13 +11320,13 @@ function scanDir(baseDir, dir, minMtime, result) {
|
|
|
11304
11320
|
}
|
|
11305
11321
|
function filterAnalyzable(files) {
|
|
11306
11322
|
return files.filter((f) => {
|
|
11307
|
-
const ext = (0,
|
|
11323
|
+
const ext = (0, import_node_path4.extname)(f).slice(1);
|
|
11308
11324
|
return ANALYZABLE_EXTENSIONS.has(ext);
|
|
11309
11325
|
});
|
|
11310
11326
|
}
|
|
11311
11327
|
function filterReviewable(files) {
|
|
11312
11328
|
return files.filter((f) => {
|
|
11313
|
-
const ext = (0,
|
|
11329
|
+
const ext = (0, import_node_path4.extname)(f).slice(1);
|
|
11314
11330
|
if (ANALYZABLE_EXTENSIONS.has(ext)) return false;
|
|
11315
11331
|
if (REVIEWABLE_EXTENSIONS.has(ext)) return true;
|
|
11316
11332
|
const basename2 = f.split("/").pop() ?? "";
|
|
@@ -11330,7 +11346,7 @@ function getCurrentCommit() {
|
|
|
11330
11346
|
|
|
11331
11347
|
// src/lib/files.ts
|
|
11332
11348
|
var import_node_fs3 = require("node:fs");
|
|
11333
|
-
var
|
|
11349
|
+
var import_node_path5 = require("node:path");
|
|
11334
11350
|
var LANG_MAP = {
|
|
11335
11351
|
// Analyzable (static analysis + Gemini)
|
|
11336
11352
|
ts: "typescript",
|
|
@@ -11398,7 +11414,7 @@ var LANG_MAP = {
|
|
|
11398
11414
|
mk: "make"
|
|
11399
11415
|
};
|
|
11400
11416
|
function detectLanguage(filepath) {
|
|
11401
|
-
const ext = (0,
|
|
11417
|
+
const ext = (0, import_node_path5.extname)(filepath).slice(1);
|
|
11402
11418
|
return LANG_MAP[ext] ?? ext;
|
|
11403
11419
|
}
|
|
11404
11420
|
function sortByMtime(files) {
|
|
@@ -11577,7 +11593,7 @@ function writeIteration(iteration, commit) {
|
|
|
11577
11593
|
}
|
|
11578
11594
|
|
|
11579
11595
|
// src/lib/static-analysis.ts
|
|
11580
|
-
var
|
|
11596
|
+
var import_node_child_process5 = require("node:child_process");
|
|
11581
11597
|
var import_node_fs5 = require("node:fs");
|
|
11582
11598
|
var SEVERITY_ORDER = {
|
|
11583
11599
|
Error: 0,
|
|
@@ -11590,7 +11606,7 @@ var SEVERITY_ORDER = {
|
|
|
11590
11606
|
};
|
|
11591
11607
|
function isCodacyAvailable() {
|
|
11592
11608
|
try {
|
|
11593
|
-
(0,
|
|
11609
|
+
(0, import_node_child_process5.execSync)("which codacy-analysis", { stdio: "pipe" });
|
|
11594
11610
|
return true;
|
|
11595
11611
|
} catch {
|
|
11596
11612
|
return false;
|
|
@@ -11614,7 +11630,7 @@ function runCodacyAnalysis(files) {
|
|
|
11614
11630
|
const fileArgs = existingFiles.join(" ");
|
|
11615
11631
|
let output;
|
|
11616
11632
|
try {
|
|
11617
|
-
output = (0,
|
|
11633
|
+
output = (0, import_node_child_process5.execSync)(
|
|
11618
11634
|
`codacy-analysis analyze --install-dependencies --files ${fileArgs} --output-format json --log-level error --parallel-tools 3`,
|
|
11619
11635
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], maxBuffer: 10 * 1024 * 1024 }
|
|
11620
11636
|
);
|
|
@@ -11668,7 +11684,7 @@ function runCodacyAnalysis(files) {
|
|
|
11668
11684
|
|
|
11669
11685
|
// src/lib/specs.ts
|
|
11670
11686
|
var import_node_fs6 = require("node:fs");
|
|
11671
|
-
var
|
|
11687
|
+
var import_node_path6 = require("node:path");
|
|
11672
11688
|
var SPEC_CANDIDATES = [
|
|
11673
11689
|
"CLAUDE.md",
|
|
11674
11690
|
"AGENTS.md",
|
|
@@ -11730,7 +11746,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
11730
11746
|
try {
|
|
11731
11747
|
const entries = (0, import_node_fs6.readdirSync)(dir, { withFileTypes: true });
|
|
11732
11748
|
for (const entry of entries) {
|
|
11733
|
-
const fullPath = (0,
|
|
11749
|
+
const fullPath = (0, import_node_path6.join)(dir, entry.name);
|
|
11734
11750
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
11735
11751
|
result.push(fullPath);
|
|
11736
11752
|
} else if (entry.isDirectory() && depth < maxDepth - 1) {
|
|
@@ -11747,7 +11763,7 @@ function discoverPlans() {
|
|
|
11747
11763
|
const result = [];
|
|
11748
11764
|
try {
|
|
11749
11765
|
const entries = (0, import_node_fs6.readdirSync)(plansDir).filter((f) => f.endsWith(".md")).map((f) => {
|
|
11750
|
-
const fullPath = (0,
|
|
11766
|
+
const fullPath = (0, import_node_path6.join)(plansDir, f);
|
|
11751
11767
|
try {
|
|
11752
11768
|
const stat = (0, import_node_fs6.statSync)(fullPath);
|
|
11753
11769
|
return { name: f, path: fullPath, mtime: stat.mtimeMs, size: stat.size };
|
|
@@ -11847,11 +11863,11 @@ async function runAnalyze(opts, globals) {
|
|
|
11847
11863
|
}
|
|
11848
11864
|
const tokenResult = await resolveToken(globals.token);
|
|
11849
11865
|
if (!tokenResult.ok) {
|
|
11850
|
-
passAndExit("Not configured yet
|
|
11866
|
+
passAndExit("Not configured yet \u2014 run /gate-setup in Claude Code to enable quality gates.");
|
|
11851
11867
|
}
|
|
11852
11868
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
11853
11869
|
if (!urlResult.ok) {
|
|
11854
|
-
passAndExit("
|
|
11870
|
+
passAndExit("Not configured yet \u2014 run /gate-setup in Claude Code to enable quality gates.");
|
|
11855
11871
|
}
|
|
11856
11872
|
const currentCommit = getCurrentCommit();
|
|
11857
11873
|
const maxIterations = parseInt(opts.maxIterations, 10);
|
|
@@ -12020,12 +12036,12 @@ async function runReview(opts, globals) {
|
|
|
12020
12036
|
const codeDelta = collectCodeDelta(allFiles);
|
|
12021
12037
|
const tokenResult = await resolveToken(globals.token);
|
|
12022
12038
|
if (!tokenResult.ok) {
|
|
12023
|
-
printError(
|
|
12039
|
+
printError("Not configured yet \u2014 run /gate-setup in Claude Code to enable quality gates.");
|
|
12024
12040
|
process.exit(0);
|
|
12025
12041
|
}
|
|
12026
12042
|
const urlResult = await resolveServiceUrl(globals.serviceUrl);
|
|
12027
12043
|
if (!urlResult.ok) {
|
|
12028
|
-
printError(
|
|
12044
|
+
printError("Not configured yet \u2014 run /gate-setup in Claude Code to enable quality gates.");
|
|
12029
12045
|
process.exit(0);
|
|
12030
12046
|
}
|
|
12031
12047
|
let specs;
|
|
@@ -12096,19 +12112,19 @@ async function runReview(opts, globals) {
|
|
|
12096
12112
|
// src/commands/init.ts
|
|
12097
12113
|
var import_node_fs9 = require("node:fs");
|
|
12098
12114
|
var import_promises8 = require("node:fs/promises");
|
|
12099
|
-
var
|
|
12100
|
-
var
|
|
12115
|
+
var import_node_path7 = require("node:path");
|
|
12116
|
+
var import_node_child_process6 = require("node:child_process");
|
|
12101
12117
|
function resolveDataDir() {
|
|
12102
12118
|
const candidates = [
|
|
12103
|
-
(0,
|
|
12119
|
+
(0, import_node_path7.join)(__dirname, "..", "data"),
|
|
12104
12120
|
// installed: node_modules/@codacy/gate-cli/data
|
|
12105
|
-
(0,
|
|
12121
|
+
(0, import_node_path7.join)(__dirname, "..", "..", "data"),
|
|
12106
12122
|
// edge case: nested resolution
|
|
12107
|
-
(0,
|
|
12123
|
+
(0, import_node_path7.join)(process.cwd(), "cli", "data")
|
|
12108
12124
|
// local dev: running from repo root
|
|
12109
12125
|
];
|
|
12110
12126
|
for (const candidate of candidates) {
|
|
12111
|
-
if ((0, import_node_fs9.existsSync)((0,
|
|
12127
|
+
if ((0, import_node_fs9.existsSync)((0, import_node_path7.join)(candidate, "skills"))) {
|
|
12112
12128
|
return candidate;
|
|
12113
12129
|
}
|
|
12114
12130
|
}
|
|
@@ -12142,42 +12158,55 @@ function registerInitCommand(program2) {
|
|
|
12142
12158
|
}
|
|
12143
12159
|
printInfo(` Node.js ${nodeVersion} \u2713`);
|
|
12144
12160
|
try {
|
|
12145
|
-
const gitVersion = (0,
|
|
12161
|
+
const gitVersion = (0, import_node_child_process6.execSync)("git --version", { encoding: "utf-8" }).trim();
|
|
12146
12162
|
printInfo(` ${gitVersion} \u2713`);
|
|
12147
12163
|
} catch {
|
|
12148
12164
|
printError("git is required but not installed. Install from https://git-scm.com");
|
|
12149
12165
|
process.exit(1);
|
|
12150
12166
|
}
|
|
12151
12167
|
try {
|
|
12152
|
-
(0,
|
|
12168
|
+
(0, import_node_child_process6.execSync)("which claude", { encoding: "utf-8" });
|
|
12153
12169
|
printInfo(" Claude Code \u2713");
|
|
12154
12170
|
} catch {
|
|
12155
12171
|
printWarn(" Claude Code not found \u2014 hooks will be configured but need Claude Code to run.");
|
|
12156
12172
|
}
|
|
12157
12173
|
try {
|
|
12158
|
-
(0,
|
|
12174
|
+
(0, import_node_child_process6.execSync)("which codacy-analysis", { encoding: "utf-8", stdio: "pipe" });
|
|
12159
12175
|
printInfo(" @codacy/analysis-cli \u2713");
|
|
12160
12176
|
} catch {
|
|
12161
|
-
|
|
12162
|
-
|
|
12177
|
+
printInfo(" Installing @codacy/analysis-cli...");
|
|
12178
|
+
try {
|
|
12179
|
+
(0, import_node_child_process6.execSync)("npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "pipe", timeout: 12e4 });
|
|
12180
|
+
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
12181
|
+
} catch {
|
|
12182
|
+
try {
|
|
12183
|
+
printWarn(" Retrying with sudo...");
|
|
12184
|
+
(0, import_node_child_process6.execSync)("sudo npm install -g @codacy/analysis-cli", { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
12185
|
+
printInfo(" @codacy/analysis-cli installed \u2713");
|
|
12186
|
+
} catch {
|
|
12187
|
+
printWarn(" Could not install @codacy/analysis-cli automatically.");
|
|
12188
|
+
printWarn(" Install manually: npm install -g @codacy/analysis-cli");
|
|
12189
|
+
printWarn(" Static analysis will be unavailable until installed.");
|
|
12190
|
+
}
|
|
12191
|
+
}
|
|
12163
12192
|
}
|
|
12164
12193
|
console.log("");
|
|
12165
12194
|
printInfo("Installing skills...");
|
|
12166
12195
|
const dataDir = resolveDataDir();
|
|
12167
|
-
const skillsSource = (0,
|
|
12196
|
+
const skillsSource = (0, import_node_path7.join)(dataDir, "skills");
|
|
12168
12197
|
const skillsDest = ".claude/skills";
|
|
12169
12198
|
const skills = ["gate-setup", "gate-analyze", "gate-status", "gate-feedback"];
|
|
12170
12199
|
let skillsInstalled = 0;
|
|
12171
12200
|
for (const skill of skills) {
|
|
12172
|
-
const src = (0,
|
|
12173
|
-
const dest = (0,
|
|
12201
|
+
const src = (0, import_node_path7.join)(skillsSource, skill);
|
|
12202
|
+
const dest = (0, import_node_path7.join)(skillsDest, skill);
|
|
12174
12203
|
if (!(0, import_node_fs9.existsSync)(src)) {
|
|
12175
12204
|
printWarn(` Skill data not found: ${skill}`);
|
|
12176
12205
|
continue;
|
|
12177
12206
|
}
|
|
12178
12207
|
if ((0, import_node_fs9.existsSync)(dest) && !force) {
|
|
12179
|
-
const srcSkill = (0,
|
|
12180
|
-
const destSkill = (0,
|
|
12208
|
+
const srcSkill = (0, import_node_path7.join)(src, "SKILL.md");
|
|
12209
|
+
const destSkill = (0, import_node_path7.join)(dest, "SKILL.md");
|
|
12181
12210
|
if ((0, import_node_fs9.existsSync)(destSkill)) {
|
|
12182
12211
|
try {
|
|
12183
12212
|
const srcContent = await (0, import_promises8.readFile)(srcSkill, "utf-8");
|
|
@@ -12206,7 +12235,7 @@ function registerInitCommand(program2) {
|
|
|
12206
12235
|
printInfo(' Run "gate hooks install --force" to overwrite.');
|
|
12207
12236
|
}
|
|
12208
12237
|
await (0, import_promises8.mkdir)(GATE_DIR, { recursive: true });
|
|
12209
|
-
const globalGateDir = (0,
|
|
12238
|
+
const globalGateDir = (0, import_node_path7.join)(process.env.HOME ?? "", ".gate");
|
|
12210
12239
|
await (0, import_promises8.mkdir)(globalGateDir, { recursive: true });
|
|
12211
12240
|
console.log("");
|
|
12212
12241
|
printInfo("GATE.md initialized!");
|
|
@@ -12224,7 +12253,7 @@ function registerInitCommand(program2) {
|
|
|
12224
12253
|
}
|
|
12225
12254
|
|
|
12226
12255
|
// src/cli.ts
|
|
12227
|
-
program.name("gate").description("CLI for GATE.md quality gate service").version("0.
|
|
12256
|
+
program.name("gate").description("CLI for GATE.md quality gate service").version("0.4.0").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
|
|
12228
12257
|
registerAuthCommands(program);
|
|
12229
12258
|
registerHooksCommands(program);
|
|
12230
12259
|
registerIntentCommands(program);
|