@codacy/gate-cli 0.14.1 → 0.14.3
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 +209 -96
- package/package.json +1 -1
package/bin/gate.js
CHANGED
|
@@ -10355,6 +10355,9 @@ var ITERATION_FILE = `${GATE_DIR}/.iteration-count`;
|
|
|
10355
10355
|
var HASH_FILE = `${GATE_DIR}/.last-pass-hash`;
|
|
10356
10356
|
var INTENT_FILE = `${GATE_DIR}/.last-intent`;
|
|
10357
10357
|
var CACHE_DIR = `${GATE_DIR}/.cache`;
|
|
10358
|
+
var DEBUG_LOG_DIR = `${GATE_DIR}/.logs`;
|
|
10359
|
+
var DEBUG_LOG_FILE = `${DEBUG_LOG_DIR}/cli.log`;
|
|
10360
|
+
var DEBUG_LOG_MAX_BYTES = 1048576;
|
|
10358
10361
|
var GATE_MD_FILE = "GATE.md";
|
|
10359
10362
|
var CLAUDE_SETTINGS_FILE = ".claude/settings.json";
|
|
10360
10363
|
var STANDARD_FILE = `${GATE_DIR}/standard.yaml`;
|
|
@@ -10588,9 +10591,54 @@ function printVerbose(msg, verbose) {
|
|
|
10588
10591
|
}
|
|
10589
10592
|
}
|
|
10590
10593
|
|
|
10594
|
+
// src/lib/debug-log.ts
|
|
10595
|
+
var import_node_fs = require("node:fs");
|
|
10596
|
+
function isEnabled() {
|
|
10597
|
+
const v = process.env.GATE_DEBUG;
|
|
10598
|
+
if (v === "0" || v === "false" || v === "off") return false;
|
|
10599
|
+
return true;
|
|
10600
|
+
}
|
|
10601
|
+
function logHttpCall(entry) {
|
|
10602
|
+
if (!isEnabled()) return;
|
|
10603
|
+
writeLine({ ts: (/* @__PURE__ */ new Date()).toISOString(), kind: "http", ...entry });
|
|
10604
|
+
}
|
|
10605
|
+
function logEvent(event, data) {
|
|
10606
|
+
if (!isEnabled()) return;
|
|
10607
|
+
writeLine({ ts: (/* @__PURE__ */ new Date()).toISOString(), kind: "event", event, ...data ?? {} });
|
|
10608
|
+
}
|
|
10609
|
+
function writeLine(obj) {
|
|
10610
|
+
try {
|
|
10611
|
+
const dir = projectPath(DEBUG_LOG_DIR);
|
|
10612
|
+
const file = projectPath(DEBUG_LOG_FILE);
|
|
10613
|
+
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
10614
|
+
rotateIfNeeded(file);
|
|
10615
|
+
(0, import_node_fs.appendFileSync)(file, JSON.stringify(obj) + "\n");
|
|
10616
|
+
} catch {
|
|
10617
|
+
}
|
|
10618
|
+
}
|
|
10619
|
+
function rotateIfNeeded(file) {
|
|
10620
|
+
try {
|
|
10621
|
+
const s = (0, import_node_fs.statSync)(file);
|
|
10622
|
+
if (s.size < DEBUG_LOG_MAX_BYTES) return;
|
|
10623
|
+
(0, import_node_fs.renameSync)(file, `${file}.1`);
|
|
10624
|
+
} catch {
|
|
10625
|
+
}
|
|
10626
|
+
}
|
|
10627
|
+
|
|
10591
10628
|
// src/lib/api-client.ts
|
|
10592
10629
|
async function apiRequest(options) {
|
|
10593
|
-
const {
|
|
10630
|
+
const {
|
|
10631
|
+
method,
|
|
10632
|
+
path,
|
|
10633
|
+
serviceUrl,
|
|
10634
|
+
token,
|
|
10635
|
+
body,
|
|
10636
|
+
verbose,
|
|
10637
|
+
timeout = 9e4,
|
|
10638
|
+
cmd = "unknown",
|
|
10639
|
+
retry = false,
|
|
10640
|
+
encodeBody = false
|
|
10641
|
+
} = options;
|
|
10594
10642
|
const url = `${serviceUrl}${path}`;
|
|
10595
10643
|
const headers = {
|
|
10596
10644
|
"Content-Type": "application/json"
|
|
@@ -10599,36 +10647,74 @@ async function apiRequest(options) {
|
|
|
10599
10647
|
headers["Authorization"] = `Bearer ${token}`;
|
|
10600
10648
|
}
|
|
10601
10649
|
printVerbose(`${method} ${url}`, verbose);
|
|
10602
|
-
|
|
10603
|
-
|
|
10650
|
+
let serializedBody;
|
|
10651
|
+
if (body !== void 0 && body !== null) {
|
|
10652
|
+
const innerJson = JSON.stringify(body);
|
|
10653
|
+
if (encodeBody) {
|
|
10654
|
+
const payload = Buffer.from(innerJson, "utf8").toString("base64");
|
|
10655
|
+
serializedBody = JSON.stringify({ encoding: "base64", payload });
|
|
10656
|
+
} else {
|
|
10657
|
+
serializedBody = innerJson;
|
|
10658
|
+
}
|
|
10659
|
+
printVerbose(`Body: ${serializedBody.slice(0, 500)}`, verbose);
|
|
10604
10660
|
}
|
|
10661
|
+
const startedAt = Date.now();
|
|
10662
|
+
const bodyBytes = serializedBody ? Buffer.byteLength(serializedBody) : 0;
|
|
10663
|
+
const logBase = { cmd, method, url, body_bytes: bodyBytes, retry, encoded: encodeBody };
|
|
10605
10664
|
let response;
|
|
10606
10665
|
try {
|
|
10607
10666
|
response = await fetch(url, {
|
|
10608
10667
|
method,
|
|
10609
10668
|
headers,
|
|
10610
|
-
body:
|
|
10669
|
+
body: serializedBody,
|
|
10611
10670
|
signal: AbortSignal.timeout(timeout)
|
|
10612
10671
|
});
|
|
10613
10672
|
} catch (err) {
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10673
|
+
const duration2 = Date.now() - startedAt;
|
|
10674
|
+
const isTimeout = err instanceof DOMException && err.name === "TimeoutError";
|
|
10675
|
+
const category = isTimeout ? "timeout" : "network";
|
|
10676
|
+
const error = isTimeout ? `Request timed out after ${timeout}ms` : `Network error: ${err.message}`;
|
|
10677
|
+
logHttpCall({ ...logBase, duration_ms: duration2, http_status: null, category, error });
|
|
10678
|
+
return { ok: false, error, category };
|
|
10618
10679
|
}
|
|
10619
10680
|
let data;
|
|
10620
10681
|
try {
|
|
10621
10682
|
data = await response.json();
|
|
10622
10683
|
} catch {
|
|
10623
|
-
|
|
10684
|
+
const duration2 = Date.now() - startedAt;
|
|
10685
|
+
const error = `Invalid JSON response (HTTP ${response.status})`;
|
|
10686
|
+
logHttpCall({
|
|
10687
|
+
...logBase,
|
|
10688
|
+
duration_ms: duration2,
|
|
10689
|
+
http_status: response.status,
|
|
10690
|
+
category: "invalid_json",
|
|
10691
|
+
error
|
|
10692
|
+
});
|
|
10693
|
+
return { ok: false, error, category: "invalid_json" };
|
|
10624
10694
|
}
|
|
10625
10695
|
printVerbose(`Response ${response.status}: ${JSON.stringify(data).slice(0, 500)}`, verbose);
|
|
10696
|
+
const duration = Date.now() - startedAt;
|
|
10626
10697
|
if (!response.ok) {
|
|
10627
10698
|
const apiErr = data;
|
|
10628
10699
|
const code = apiErr?.error?.code ?? "UNKNOWN";
|
|
10629
10700
|
const message = apiErr?.error?.message ?? `HTTP ${response.status}`;
|
|
10630
|
-
|
|
10701
|
+
const category = response.status >= 500 ? "http_5xx" : "http_4xx";
|
|
10702
|
+
const error = `${code}: ${message}`;
|
|
10703
|
+
logHttpCall({
|
|
10704
|
+
...logBase,
|
|
10705
|
+
duration_ms: duration,
|
|
10706
|
+
http_status: response.status,
|
|
10707
|
+
category,
|
|
10708
|
+
error
|
|
10709
|
+
});
|
|
10710
|
+
return { ok: false, error, category };
|
|
10631
10711
|
}
|
|
10712
|
+
logHttpCall({
|
|
10713
|
+
...logBase,
|
|
10714
|
+
duration_ms: duration,
|
|
10715
|
+
http_status: response.status,
|
|
10716
|
+
category: "ok"
|
|
10717
|
+
});
|
|
10632
10718
|
return { ok: true, data };
|
|
10633
10719
|
}
|
|
10634
10720
|
|
|
@@ -10858,7 +10944,7 @@ function registerHooksCommands(program2) {
|
|
|
10858
10944
|
|
|
10859
10945
|
// src/lib/conversation-buffer.ts
|
|
10860
10946
|
var import_promises5 = require("node:fs/promises");
|
|
10861
|
-
var
|
|
10947
|
+
var import_node_fs2 = require("node:fs");
|
|
10862
10948
|
var import_node_child_process4 = require("node:child_process");
|
|
10863
10949
|
function stripImageReferences(text) {
|
|
10864
10950
|
return text.replace(/\[Image #\d+\]/g, "[screenshot \u2014 not available for review]");
|
|
@@ -10890,7 +10976,7 @@ async function appendToConversationBuffer(prompt, sessionId) {
|
|
|
10890
10976
|
}
|
|
10891
10977
|
async function readAndClearConversationBuffer() {
|
|
10892
10978
|
try {
|
|
10893
|
-
if ((0,
|
|
10979
|
+
if ((0, import_node_fs2.existsSync)(CONVERSATION_BUFFER_FILE)) {
|
|
10894
10980
|
const entries = await readBufferEntries();
|
|
10895
10981
|
await (0, import_promises5.unlink)(CONVERSATION_BUFFER_FILE).catch(() => {
|
|
10896
10982
|
});
|
|
@@ -10901,7 +10987,7 @@ async function readAndClearConversationBuffer() {
|
|
|
10901
10987
|
};
|
|
10902
10988
|
}
|
|
10903
10989
|
}
|
|
10904
|
-
if ((0,
|
|
10990
|
+
if ((0, import_node_fs2.existsSync)(INTENT_FILE)) {
|
|
10905
10991
|
try {
|
|
10906
10992
|
const content = await (0, import_promises5.readFile)(INTENT_FILE, "utf-8");
|
|
10907
10993
|
await (0, import_promises5.unlink)(INTENT_FILE).catch(() => {
|
|
@@ -10957,12 +11043,12 @@ function getRecentCommitMessages() {
|
|
|
10957
11043
|
}
|
|
10958
11044
|
|
|
10959
11045
|
// src/commands/intent.ts
|
|
10960
|
-
var
|
|
11046
|
+
var import_node_fs3 = require("node:fs");
|
|
10961
11047
|
function registerIntentCommands(program2) {
|
|
10962
11048
|
const intent = program2.command("intent").description("Manage intent capture");
|
|
10963
11049
|
intent.command("capture").description("Capture user intent from stdin (used by UserPromptSubmit hook)").action(async () => {
|
|
10964
11050
|
try {
|
|
10965
|
-
if (!(0,
|
|
11051
|
+
if (!(0, import_node_fs3.existsSync)(GATE_DIR)) {
|
|
10966
11052
|
process.exit(0);
|
|
10967
11053
|
}
|
|
10968
11054
|
const chunks = [];
|
|
@@ -11301,17 +11387,17 @@ function registerFeedbackCommand(program2) {
|
|
|
11301
11387
|
|
|
11302
11388
|
// src/lib/git.ts
|
|
11303
11389
|
var import_node_child_process5 = require("node:child_process");
|
|
11304
|
-
var
|
|
11390
|
+
var import_node_fs4 = require("node:fs");
|
|
11305
11391
|
var import_node_path4 = require("node:path");
|
|
11306
11392
|
function resolveFile(relpath) {
|
|
11307
|
-
if ((0,
|
|
11308
|
-
if ((0,
|
|
11393
|
+
if ((0, import_node_fs4.existsSync)(relpath)) return relpath;
|
|
11394
|
+
if ((0, import_node_fs4.existsSync)(".claude/worktrees")) {
|
|
11309
11395
|
try {
|
|
11310
|
-
const entries = (0,
|
|
11396
|
+
const entries = (0, import_node_fs4.readdirSync)(".claude/worktrees", { withFileTypes: true });
|
|
11311
11397
|
for (const entry of entries) {
|
|
11312
11398
|
if (!entry.isDirectory()) continue;
|
|
11313
11399
|
const candidate = (0, import_node_path4.join)(".claude/worktrees", entry.name, relpath);
|
|
11314
|
-
if ((0,
|
|
11400
|
+
if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
|
|
11315
11401
|
}
|
|
11316
11402
|
} catch {
|
|
11317
11403
|
}
|
|
@@ -11363,10 +11449,10 @@ function getChangedFiles() {
|
|
|
11363
11449
|
function getWorktreeFiles() {
|
|
11364
11450
|
const result = [];
|
|
11365
11451
|
const worktreeDir = ".claude/worktrees";
|
|
11366
|
-
if (!(0,
|
|
11452
|
+
if (!(0, import_node_fs4.existsSync)(worktreeDir)) return result;
|
|
11367
11453
|
try {
|
|
11368
11454
|
const fiveMinAgo = Date.now() - 5 * 60 * 1e3;
|
|
11369
|
-
const entries = (0,
|
|
11455
|
+
const entries = (0, import_node_fs4.readdirSync)(worktreeDir, { withFileTypes: true });
|
|
11370
11456
|
for (const entry of entries) {
|
|
11371
11457
|
if (!entry.isDirectory()) continue;
|
|
11372
11458
|
const wtDir = (0, import_node_path4.join)(worktreeDir, entry.name);
|
|
@@ -11378,7 +11464,7 @@ function getWorktreeFiles() {
|
|
|
11378
11464
|
}
|
|
11379
11465
|
function scanDir(baseDir, dir, minMtime, result) {
|
|
11380
11466
|
try {
|
|
11381
|
-
const entries = (0,
|
|
11467
|
+
const entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true });
|
|
11382
11468
|
for (const entry of entries) {
|
|
11383
11469
|
const fullPath = (0, import_node_path4.join)(dir, entry.name);
|
|
11384
11470
|
if (entry.isDirectory()) {
|
|
@@ -11388,7 +11474,7 @@ function scanDir(baseDir, dir, minMtime, result) {
|
|
|
11388
11474
|
const ext = (0, import_node_path4.extname)(entry.name).slice(1);
|
|
11389
11475
|
if (!ANALYZABLE_EXTENSIONS.has(ext)) continue;
|
|
11390
11476
|
try {
|
|
11391
|
-
const stat = (0,
|
|
11477
|
+
const stat = (0, import_node_fs4.statSync)(fullPath);
|
|
11392
11478
|
if (stat.mtimeMs >= minMtime) {
|
|
11393
11479
|
const relPath = fullPath.slice(baseDir.length + 1);
|
|
11394
11480
|
result.push(relPath);
|
|
@@ -11427,7 +11513,7 @@ function getCurrentCommit() {
|
|
|
11427
11513
|
}
|
|
11428
11514
|
|
|
11429
11515
|
// src/lib/files.ts
|
|
11430
|
-
var
|
|
11516
|
+
var import_node_fs5 = require("node:fs");
|
|
11431
11517
|
var import_node_path5 = require("node:path");
|
|
11432
11518
|
var LANG_MAP = {
|
|
11433
11519
|
// Analyzable (static analysis + Gemini)
|
|
@@ -11504,7 +11590,7 @@ function sortByMtime(files) {
|
|
|
11504
11590
|
const resolved = resolveFile(f);
|
|
11505
11591
|
if (!resolved) return null;
|
|
11506
11592
|
try {
|
|
11507
|
-
const stat = (0,
|
|
11593
|
+
const stat = (0, import_node_fs5.statSync)(resolved);
|
|
11508
11594
|
return { path: f, resolved, mtime: stat.mtimeMs };
|
|
11509
11595
|
} catch {
|
|
11510
11596
|
return null;
|
|
@@ -11526,7 +11612,7 @@ function collectCodeDelta(files, opts) {
|
|
|
11526
11612
|
if (!resolved) continue;
|
|
11527
11613
|
let size;
|
|
11528
11614
|
try {
|
|
11529
|
-
size = (0,
|
|
11615
|
+
size = (0, import_node_fs5.statSync)(resolved).size;
|
|
11530
11616
|
} catch {
|
|
11531
11617
|
continue;
|
|
11532
11618
|
}
|
|
@@ -11534,7 +11620,7 @@ function collectCodeDelta(files, opts) {
|
|
|
11534
11620
|
if (totalSize + size > maxTotalBytes) break;
|
|
11535
11621
|
let content;
|
|
11536
11622
|
try {
|
|
11537
|
-
content = (0,
|
|
11623
|
+
content = (0, import_node_fs5.readFileSync)(resolved, "utf-8");
|
|
11538
11624
|
} catch {
|
|
11539
11625
|
continue;
|
|
11540
11626
|
}
|
|
@@ -11557,12 +11643,12 @@ function collectCodeDelta(files, opts) {
|
|
|
11557
11643
|
}
|
|
11558
11644
|
|
|
11559
11645
|
// src/lib/debounce.ts
|
|
11560
|
-
var
|
|
11646
|
+
var import_node_fs6 = require("node:fs");
|
|
11561
11647
|
var import_node_crypto = require("node:crypto");
|
|
11562
11648
|
function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS) {
|
|
11563
|
-
if (!(0,
|
|
11649
|
+
if (!(0, import_node_fs6.existsSync)(DEBOUNCE_FILE)) return null;
|
|
11564
11650
|
try {
|
|
11565
|
-
const lastTs = parseInt((0,
|
|
11651
|
+
const lastTs = parseInt((0, import_node_fs6.readFileSync)(DEBOUNCE_FILE, "utf-8").trim(), 10);
|
|
11566
11652
|
const nowTs = Math.floor(Date.now() / 1e3);
|
|
11567
11653
|
const elapsed = nowTs - lastTs;
|
|
11568
11654
|
if (elapsed < debounceSeconds) {
|
|
@@ -11574,10 +11660,10 @@ function checkDebounce(debounceSeconds = DEBOUNCE_SECONDS) {
|
|
|
11574
11660
|
}
|
|
11575
11661
|
function checkMtime(files, bypassForRecentCommits) {
|
|
11576
11662
|
if (bypassForRecentCommits) return null;
|
|
11577
|
-
if (!(0,
|
|
11663
|
+
if (!(0, import_node_fs6.existsSync)(DEBOUNCE_FILE)) return null;
|
|
11578
11664
|
let debounceTime;
|
|
11579
11665
|
try {
|
|
11580
|
-
debounceTime = (0,
|
|
11666
|
+
debounceTime = (0, import_node_fs6.statSync)(DEBOUNCE_FILE).mtimeMs;
|
|
11581
11667
|
} catch {
|
|
11582
11668
|
return null;
|
|
11583
11669
|
}
|
|
@@ -11585,7 +11671,7 @@ function checkMtime(files, bypassForRecentCommits) {
|
|
|
11585
11671
|
const resolved = resolveFile(f);
|
|
11586
11672
|
if (!resolved) continue;
|
|
11587
11673
|
try {
|
|
11588
|
-
const stat = (0,
|
|
11674
|
+
const stat = (0, import_node_fs6.statSync)(resolved);
|
|
11589
11675
|
if (stat.mtimeMs > debounceTime) {
|
|
11590
11676
|
return null;
|
|
11591
11677
|
}
|
|
@@ -11601,8 +11687,8 @@ function computeContentHash(files) {
|
|
|
11601
11687
|
for (const f of sorted) {
|
|
11602
11688
|
const resolved = resolveFile(f) ?? f;
|
|
11603
11689
|
try {
|
|
11604
|
-
if ((0,
|
|
11605
|
-
hash.update((0,
|
|
11690
|
+
if ((0, import_node_fs6.existsSync)(resolved)) {
|
|
11691
|
+
hash.update((0, import_node_fs6.readFileSync)(resolved));
|
|
11606
11692
|
}
|
|
11607
11693
|
} catch {
|
|
11608
11694
|
}
|
|
@@ -11611,9 +11697,9 @@ function computeContentHash(files) {
|
|
|
11611
11697
|
}
|
|
11612
11698
|
function checkContentHash(files) {
|
|
11613
11699
|
const hash = computeContentHash(files);
|
|
11614
|
-
if ((0,
|
|
11700
|
+
if ((0, import_node_fs6.existsSync)(HASH_FILE)) {
|
|
11615
11701
|
try {
|
|
11616
|
-
const storedHash = (0,
|
|
11702
|
+
const storedHash = (0, import_node_fs6.readFileSync)(HASH_FILE, "utf-8").trim();
|
|
11617
11703
|
if (hash === storedHash) {
|
|
11618
11704
|
return { skip: "No source changes since last analysis", hash };
|
|
11619
11705
|
}
|
|
@@ -11623,23 +11709,23 @@ function checkContentHash(files) {
|
|
|
11623
11709
|
return { skip: null, hash };
|
|
11624
11710
|
}
|
|
11625
11711
|
function recordAnalysisStart() {
|
|
11626
|
-
(0,
|
|
11627
|
-
(0,
|
|
11712
|
+
(0, import_node_fs6.mkdirSync)(GATE_DIR, { recursive: true });
|
|
11713
|
+
(0, import_node_fs6.writeFileSync)(DEBOUNCE_FILE, String(Math.floor(Date.now() / 1e3)));
|
|
11628
11714
|
}
|
|
11629
11715
|
function recordPassHash(hash) {
|
|
11630
|
-
(0,
|
|
11716
|
+
(0, import_node_fs6.writeFileSync)(HASH_FILE, hash);
|
|
11631
11717
|
}
|
|
11632
11718
|
function narrowToRecent(files) {
|
|
11633
|
-
if (!(0,
|
|
11719
|
+
if (!(0, import_node_fs6.existsSync)(DEBOUNCE_FILE)) return files;
|
|
11634
11720
|
let debounceTime;
|
|
11635
11721
|
try {
|
|
11636
|
-
debounceTime = (0,
|
|
11722
|
+
debounceTime = (0, import_node_fs6.statSync)(DEBOUNCE_FILE).mtimeMs;
|
|
11637
11723
|
} catch {
|
|
11638
11724
|
return files;
|
|
11639
11725
|
}
|
|
11640
11726
|
const recent = files.filter((f) => {
|
|
11641
11727
|
try {
|
|
11642
|
-
return (0,
|
|
11728
|
+
return (0, import_node_fs6.existsSync)(f) && (0, import_node_fs6.statSync)(f).mtimeMs > debounceTime;
|
|
11643
11729
|
} catch {
|
|
11644
11730
|
return false;
|
|
11645
11731
|
}
|
|
@@ -11647,9 +11733,9 @@ function narrowToRecent(files) {
|
|
|
11647
11733
|
return recent.length > 0 ? recent : files;
|
|
11648
11734
|
}
|
|
11649
11735
|
function readIteration(currentCommit, _contentHash) {
|
|
11650
|
-
if (!(0,
|
|
11736
|
+
if (!(0, import_node_fs6.existsSync)(ITERATION_FILE)) return 1;
|
|
11651
11737
|
try {
|
|
11652
|
-
const stored = (0,
|
|
11738
|
+
const stored = (0, import_node_fs6.readFileSync)(ITERATION_FILE, "utf-8").trim();
|
|
11653
11739
|
const parts = stored.split(":");
|
|
11654
11740
|
const iter = parseInt(parts[0], 10);
|
|
11655
11741
|
const storedCommit = parts[1] ?? "";
|
|
@@ -11677,14 +11763,14 @@ function checkMaxIterations(currentCommit, maxIterations = MAX_ITERATIONS, conte
|
|
|
11677
11763
|
return { skip: null, iteration };
|
|
11678
11764
|
}
|
|
11679
11765
|
function writeIteration(iteration, commit, _contentHash) {
|
|
11680
|
-
(0,
|
|
11766
|
+
(0, import_node_fs6.mkdirSync)(GATE_DIR, { recursive: true });
|
|
11681
11767
|
const ts = Math.floor(Date.now() / 1e3);
|
|
11682
|
-
(0,
|
|
11768
|
+
(0, import_node_fs6.writeFileSync)(ITERATION_FILE, `${iteration}:${commit}:${ts}`);
|
|
11683
11769
|
}
|
|
11684
11770
|
|
|
11685
11771
|
// src/lib/static-analysis.ts
|
|
11686
11772
|
var import_node_child_process6 = require("node:child_process");
|
|
11687
|
-
var
|
|
11773
|
+
var import_node_fs7 = require("node:fs");
|
|
11688
11774
|
var SEVERITY_ORDER = {
|
|
11689
11775
|
Error: 0,
|
|
11690
11776
|
Critical: 0,
|
|
@@ -11711,7 +11797,7 @@ function runCodacyAnalysis(files) {
|
|
|
11711
11797
|
if (files.length === 0) return empty;
|
|
11712
11798
|
const existingFiles = files.filter((f) => {
|
|
11713
11799
|
try {
|
|
11714
|
-
return (0,
|
|
11800
|
+
return (0, import_node_fs7.existsSync)(f);
|
|
11715
11801
|
} catch {
|
|
11716
11802
|
return false;
|
|
11717
11803
|
}
|
|
@@ -11773,7 +11859,7 @@ function runCodacyAnalysis(files) {
|
|
|
11773
11859
|
}
|
|
11774
11860
|
|
|
11775
11861
|
// src/lib/specs.ts
|
|
11776
|
-
var
|
|
11862
|
+
var import_node_fs8 = require("node:fs");
|
|
11777
11863
|
var import_node_path6 = require("node:path");
|
|
11778
11864
|
var SPEC_CANDIDATES = [
|
|
11779
11865
|
"CLAUDE.md",
|
|
@@ -11798,15 +11884,15 @@ function discoverSpecs() {
|
|
|
11798
11884
|
if (result.length >= MAX_SPEC_FILES) return false;
|
|
11799
11885
|
if (totalBytes >= MAX_TOTAL_SPEC_BYTES) return false;
|
|
11800
11886
|
if (seen.has(specPath)) return true;
|
|
11801
|
-
if (!(0,
|
|
11887
|
+
if (!(0, import_node_fs8.existsSync)(specPath)) return true;
|
|
11802
11888
|
seen.add(specPath);
|
|
11803
11889
|
const remaining = MAX_TOTAL_SPEC_BYTES - totalBytes;
|
|
11804
11890
|
const readBytes = Math.min(MAX_SPEC_FILE_BYTES, remaining);
|
|
11805
11891
|
try {
|
|
11806
11892
|
const buf = Buffer.alloc(readBytes);
|
|
11807
|
-
const fd = (0,
|
|
11808
|
-
const bytesRead = (0,
|
|
11809
|
-
(0,
|
|
11893
|
+
const fd = (0, import_node_fs8.openSync)(specPath, "r");
|
|
11894
|
+
const bytesRead = (0, import_node_fs8.readSync)(fd, buf, 0, readBytes, 0);
|
|
11895
|
+
(0, import_node_fs8.closeSync)(fd);
|
|
11810
11896
|
const content = buf.slice(0, bytesRead).toString("utf-8");
|
|
11811
11897
|
if (!content) return true;
|
|
11812
11898
|
result.push({ path: specPath, content });
|
|
@@ -11819,7 +11905,7 @@ function discoverSpecs() {
|
|
|
11819
11905
|
if (!addSpec(candidate)) break;
|
|
11820
11906
|
}
|
|
11821
11907
|
for (const dir of ["spec", "docs"]) {
|
|
11822
|
-
if (!(0,
|
|
11908
|
+
if (!(0, import_node_fs8.existsSync)(dir)) continue;
|
|
11823
11909
|
try {
|
|
11824
11910
|
const mdFiles = findMdFiles(dir, 2).sort();
|
|
11825
11911
|
for (const mdFile of mdFiles) {
|
|
@@ -11834,7 +11920,7 @@ function findMdFiles(dir, maxDepth, depth = 0) {
|
|
|
11834
11920
|
if (depth >= maxDepth) return [];
|
|
11835
11921
|
const result = [];
|
|
11836
11922
|
try {
|
|
11837
|
-
const entries = (0,
|
|
11923
|
+
const entries = (0, import_node_fs8.readdirSync)(dir, { withFileTypes: true });
|
|
11838
11924
|
for (const entry of entries) {
|
|
11839
11925
|
const fullPath = (0, import_node_path6.join)(dir, entry.name);
|
|
11840
11926
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -11853,14 +11939,14 @@ function discoverPlans() {
|
|
|
11853
11939
|
const candidates = [];
|
|
11854
11940
|
const seen = /* @__PURE__ */ new Set();
|
|
11855
11941
|
for (const plansDir of [localPlansDir, homePlansDir]) {
|
|
11856
|
-
if (!(0,
|
|
11942
|
+
if (!(0, import_node_fs8.existsSync)(plansDir)) continue;
|
|
11857
11943
|
try {
|
|
11858
|
-
for (const f of (0,
|
|
11944
|
+
for (const f of (0, import_node_fs8.readdirSync)(plansDir)) {
|
|
11859
11945
|
if (!f.endsWith(".md") || seen.has(f)) continue;
|
|
11860
11946
|
seen.add(f);
|
|
11861
11947
|
const fullPath = (0, import_node_path6.join)(plansDir, f);
|
|
11862
11948
|
try {
|
|
11863
|
-
const stat = (0,
|
|
11949
|
+
const stat = (0, import_node_fs8.statSync)(fullPath);
|
|
11864
11950
|
candidates.push({ name: f, path: fullPath, mtime: stat.mtimeMs, size: stat.size });
|
|
11865
11951
|
} catch {
|
|
11866
11952
|
}
|
|
@@ -11873,7 +11959,7 @@ function discoverPlans() {
|
|
|
11873
11959
|
for (const entry of candidates.slice(0, MAX_PLAN_FILES)) {
|
|
11874
11960
|
if (entry.size > MAX_PLAN_FILE_BYTES) continue;
|
|
11875
11961
|
try {
|
|
11876
|
-
const content = (0,
|
|
11962
|
+
const content = (0, import_node_fs8.readFileSync)(entry.path, "utf-8");
|
|
11877
11963
|
result.push({ name: entry.name, content });
|
|
11878
11964
|
} catch {
|
|
11879
11965
|
}
|
|
@@ -11882,19 +11968,19 @@ function discoverPlans() {
|
|
|
11882
11968
|
}
|
|
11883
11969
|
|
|
11884
11970
|
// src/lib/snapshot.ts
|
|
11885
|
-
var
|
|
11971
|
+
var import_node_fs9 = require("node:fs");
|
|
11886
11972
|
var import_node_path7 = require("node:path");
|
|
11887
11973
|
var import_node_child_process7 = require("node:child_process");
|
|
11888
11974
|
function generateSnapshotDiffs(files) {
|
|
11889
|
-
if (!(0,
|
|
11975
|
+
if (!(0, import_node_fs9.existsSync)(SNAPSHOT_DIR)) {
|
|
11890
11976
|
return { diffs: [], has_snapshots: false };
|
|
11891
11977
|
}
|
|
11892
11978
|
const diffs = [];
|
|
11893
11979
|
for (const file of files) {
|
|
11894
11980
|
const snapshotPath = (0, import_node_path7.join)(SNAPSHOT_DIR, file.path);
|
|
11895
11981
|
const language = file.language ?? detectLanguage(file.path);
|
|
11896
|
-
if ((0,
|
|
11897
|
-
const oldContent = (0,
|
|
11982
|
+
if ((0, import_node_fs9.existsSync)(snapshotPath)) {
|
|
11983
|
+
const oldContent = (0, import_node_fs9.readFileSync)(snapshotPath, "utf-8");
|
|
11898
11984
|
if (oldContent === file.content) continue;
|
|
11899
11985
|
const diff = computeDiff(oldContent, file.content, file.path);
|
|
11900
11986
|
if (diff) {
|
|
@@ -11920,8 +12006,8 @@ function saveSnapshots(files) {
|
|
|
11920
12006
|
for (const file of files) {
|
|
11921
12007
|
const snapshotPath = (0, import_node_path7.join)(SNAPSHOT_DIR, file.path);
|
|
11922
12008
|
snapshotPaths.add(snapshotPath);
|
|
11923
|
-
(0,
|
|
11924
|
-
(0,
|
|
12009
|
+
(0, import_node_fs9.mkdirSync)((0, import_node_path7.dirname)(snapshotPath), { recursive: true });
|
|
12010
|
+
(0, import_node_fs9.writeFileSync)(snapshotPath, file.content);
|
|
11925
12011
|
}
|
|
11926
12012
|
cleanStaleSnapshots(SNAPSHOT_DIR, snapshotPaths);
|
|
11927
12013
|
}
|
|
@@ -11929,9 +12015,9 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
11929
12015
|
const tmpOld = (0, import_node_path7.join)(SNAPSHOT_DIR, ".diff-old.tmp");
|
|
11930
12016
|
const tmpNew = (0, import_node_path7.join)(SNAPSHOT_DIR, ".diff-new.tmp");
|
|
11931
12017
|
try {
|
|
11932
|
-
(0,
|
|
11933
|
-
(0,
|
|
11934
|
-
(0,
|
|
12018
|
+
(0, import_node_fs9.mkdirSync)(SNAPSHOT_DIR, { recursive: true });
|
|
12019
|
+
(0, import_node_fs9.writeFileSync)(tmpOld, oldContent);
|
|
12020
|
+
(0, import_node_fs9.writeFileSync)(tmpNew, newContent);
|
|
11935
12021
|
const result = (0, import_node_child_process7.execSync)(
|
|
11936
12022
|
`git diff --no-index --unified=10 -- "${tmpOld}" "${tmpNew}"`,
|
|
11937
12023
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
@@ -11945,32 +12031,32 @@ function computeDiff(oldContent, newContent, filePath) {
|
|
|
11945
12031
|
return null;
|
|
11946
12032
|
} finally {
|
|
11947
12033
|
try {
|
|
11948
|
-
(0,
|
|
12034
|
+
(0, import_node_fs9.unlinkSync)(tmpOld);
|
|
11949
12035
|
} catch {
|
|
11950
12036
|
}
|
|
11951
12037
|
try {
|
|
11952
|
-
(0,
|
|
12038
|
+
(0, import_node_fs9.unlinkSync)(tmpNew);
|
|
11953
12039
|
} catch {
|
|
11954
12040
|
}
|
|
11955
12041
|
}
|
|
11956
12042
|
}
|
|
11957
12043
|
function cleanStaleSnapshots(dir, keepSet) {
|
|
11958
|
-
if (!(0,
|
|
12044
|
+
if (!(0, import_node_fs9.existsSync)(dir)) return;
|
|
11959
12045
|
try {
|
|
11960
|
-
const entries = (0,
|
|
12046
|
+
const entries = (0, import_node_fs9.readdirSync)(dir, { withFileTypes: true });
|
|
11961
12047
|
for (const entry of entries) {
|
|
11962
12048
|
if (entry.name.startsWith(".")) continue;
|
|
11963
12049
|
const fullPath = (0, import_node_path7.join)(dir, entry.name);
|
|
11964
12050
|
if (entry.isDirectory()) {
|
|
11965
12051
|
cleanStaleSnapshots(fullPath, keepSet);
|
|
11966
12052
|
try {
|
|
11967
|
-
const remaining = (0,
|
|
11968
|
-
if (remaining.length === 0) (0,
|
|
12053
|
+
const remaining = (0, import_node_fs9.readdirSync)(fullPath);
|
|
12054
|
+
if (remaining.length === 0) (0, import_node_fs9.rmdirSync)(fullPath);
|
|
11969
12055
|
} catch {
|
|
11970
12056
|
}
|
|
11971
12057
|
} else if (!keepSet.has(fullPath)) {
|
|
11972
12058
|
try {
|
|
11973
|
-
(0,
|
|
12059
|
+
(0, import_node_fs9.unlinkSync)(fullPath);
|
|
11974
12060
|
} catch {
|
|
11975
12061
|
}
|
|
11976
12062
|
}
|
|
@@ -11980,14 +12066,14 @@ function cleanStaleSnapshots(dir, keepSet) {
|
|
|
11980
12066
|
}
|
|
11981
12067
|
|
|
11982
12068
|
// src/lib/offline.ts
|
|
11983
|
-
var
|
|
12069
|
+
var import_node_fs10 = require("node:fs");
|
|
11984
12070
|
var import_node_crypto2 = require("node:crypto");
|
|
11985
12071
|
function cacheRequest(body) {
|
|
11986
12072
|
try {
|
|
11987
|
-
(0,
|
|
12073
|
+
(0, import_node_fs10.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
11988
12074
|
const suffix = (0, import_node_crypto2.randomBytes)(4).toString("hex");
|
|
11989
12075
|
const filename = `pending-${Math.floor(Date.now() / 1e3)}-${suffix}.json`;
|
|
11990
|
-
(0,
|
|
12076
|
+
(0, import_node_fs10.writeFileSync)(`${CACHE_DIR}/${filename}`, JSON.stringify(body));
|
|
11991
12077
|
} catch {
|
|
11992
12078
|
}
|
|
11993
12079
|
}
|
|
@@ -12070,7 +12156,7 @@ function detectAnalysisMode(noFilesChanged, assistantResponse, conversationPromp
|
|
|
12070
12156
|
}
|
|
12071
12157
|
|
|
12072
12158
|
// src/lib/transcript.ts
|
|
12073
|
-
var
|
|
12159
|
+
var import_node_fs11 = require("node:fs");
|
|
12074
12160
|
var MAX_READ_BYTES = 256 * 1024;
|
|
12075
12161
|
var SMALL_FILE_BYTES = 64 * 1024;
|
|
12076
12162
|
var MAX_FILES_LIST = 20;
|
|
@@ -12092,14 +12178,14 @@ async function extractActionSummary(transcriptPath) {
|
|
|
12092
12178
|
function readTurnLines(transcriptPath) {
|
|
12093
12179
|
let size;
|
|
12094
12180
|
try {
|
|
12095
|
-
size = (0,
|
|
12181
|
+
size = (0, import_node_fs11.statSync)(transcriptPath).size;
|
|
12096
12182
|
} catch {
|
|
12097
12183
|
return null;
|
|
12098
12184
|
}
|
|
12099
12185
|
if (size === 0) return null;
|
|
12100
12186
|
let raw;
|
|
12101
12187
|
if (size <= SMALL_FILE_BYTES) {
|
|
12102
|
-
raw = (0,
|
|
12188
|
+
raw = (0, import_node_fs11.readFileSync)(transcriptPath, "utf-8");
|
|
12103
12189
|
} else {
|
|
12104
12190
|
const buf = Buffer.alloc(Math.min(MAX_READ_BYTES, size));
|
|
12105
12191
|
const fd = require("node:fs").openSync(transcriptPath, "r");
|
|
@@ -12463,19 +12549,46 @@ async function runAnalyze(opts, globals) {
|
|
|
12463
12549
|
}
|
|
12464
12550
|
requestBody.intent_context = intentContext;
|
|
12465
12551
|
}
|
|
12466
|
-
const
|
|
12552
|
+
const ANALYZE_TIMEOUT_MS = 1e5;
|
|
12553
|
+
let result = await apiRequest({
|
|
12467
12554
|
method: "POST",
|
|
12468
12555
|
path: "/analyze",
|
|
12469
12556
|
serviceUrl: urlResult.data,
|
|
12470
12557
|
token: tokenResult.data.token,
|
|
12471
12558
|
body: requestBody,
|
|
12472
12559
|
verbose: globals.verbose,
|
|
12473
|
-
timeout:
|
|
12560
|
+
timeout: ANALYZE_TIMEOUT_MS,
|
|
12561
|
+
cmd: "analyze",
|
|
12562
|
+
encodeBody: true
|
|
12474
12563
|
});
|
|
12564
|
+
if (!result.ok && (result.category === "network" || result.category === "timeout")) {
|
|
12565
|
+
logEvent("analyze_warm_retry", { first_error: result.error, category: result.category });
|
|
12566
|
+
await apiRequest({
|
|
12567
|
+
method: "GET",
|
|
12568
|
+
path: "/memory",
|
|
12569
|
+
serviceUrl: urlResult.data,
|
|
12570
|
+
token: tokenResult.data.token,
|
|
12571
|
+
verbose: globals.verbose,
|
|
12572
|
+
timeout: 15e3,
|
|
12573
|
+
cmd: "analyze_warmup"
|
|
12574
|
+
});
|
|
12575
|
+
result = await apiRequest({
|
|
12576
|
+
method: "POST",
|
|
12577
|
+
path: "/analyze",
|
|
12578
|
+
serviceUrl: urlResult.data,
|
|
12579
|
+
token: tokenResult.data.token,
|
|
12580
|
+
body: requestBody,
|
|
12581
|
+
verbose: globals.verbose,
|
|
12582
|
+
timeout: ANALYZE_TIMEOUT_MS,
|
|
12583
|
+
cmd: "analyze",
|
|
12584
|
+
retry: true,
|
|
12585
|
+
encodeBody: true
|
|
12586
|
+
});
|
|
12587
|
+
}
|
|
12475
12588
|
if (!result.ok) {
|
|
12476
12589
|
cacheRequest(requestBody);
|
|
12477
12590
|
const fallback = buildOfflineFallback(
|
|
12478
|
-
`GATE.md
|
|
12591
|
+
`GATE.md offline \u2014 ${result.error}`,
|
|
12479
12592
|
staticResults
|
|
12480
12593
|
);
|
|
12481
12594
|
printJsonCompact(fallback);
|
|
@@ -12587,7 +12700,7 @@ async function runAnalyze(opts, globals) {
|
|
|
12587
12700
|
}
|
|
12588
12701
|
|
|
12589
12702
|
// src/commands/review.ts
|
|
12590
|
-
var
|
|
12703
|
+
var import_node_fs12 = require("node:fs");
|
|
12591
12704
|
function registerReviewCommand(program2) {
|
|
12592
12705
|
program2.command("review").description("Run on-demand GATE.md analysis (advisory, never blocks)").requiredOption("--files <paths>", "Comma-separated file list").option("--changed <paths>", "Subset of --files that were modified").option("--intent <text>", "User intent description (max 2000 chars)").option("--specs <paths>", "Comma-separated spec file paths").option("--json", "Output raw JSON response").action(async (opts) => {
|
|
12593
12706
|
const globals = program2.opts();
|
|
@@ -12606,7 +12719,7 @@ async function runReview(opts, globals) {
|
|
|
12606
12719
|
const securityFiles = filterSecurity(allFiles);
|
|
12607
12720
|
let staticResults;
|
|
12608
12721
|
if (isCodacyAvailable()) {
|
|
12609
|
-
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0,
|
|
12722
|
+
const scannable = Array.from(/* @__PURE__ */ new Set([...analyzable, ...securityFiles])).filter((f) => (0, import_node_fs12.existsSync)(f) || resolveFile(f) !== null);
|
|
12610
12723
|
staticResults = runCodacyAnalysis(scannable);
|
|
12611
12724
|
} else {
|
|
12612
12725
|
staticResults = {
|
|
@@ -12631,7 +12744,7 @@ async function runReview(opts, globals) {
|
|
|
12631
12744
|
const specPaths = opts.specs.split(",").map((f) => f.trim()).filter(Boolean);
|
|
12632
12745
|
specs = [];
|
|
12633
12746
|
for (const p of specPaths) {
|
|
12634
|
-
if (!(0,
|
|
12747
|
+
if (!(0, import_node_fs12.existsSync)(p)) continue;
|
|
12635
12748
|
try {
|
|
12636
12749
|
const { readFileSync: readFileSync6 } = await import("node:fs");
|
|
12637
12750
|
const content = readFileSync6(p, "utf-8");
|
|
@@ -12692,7 +12805,7 @@ async function runReview(opts, globals) {
|
|
|
12692
12805
|
}
|
|
12693
12806
|
|
|
12694
12807
|
// src/commands/init.ts
|
|
12695
|
-
var
|
|
12808
|
+
var import_node_fs13 = require("node:fs");
|
|
12696
12809
|
var import_promises8 = require("node:fs/promises");
|
|
12697
12810
|
var import_node_path8 = require("node:path");
|
|
12698
12811
|
var import_node_child_process8 = require("node:child_process");
|
|
@@ -12706,7 +12819,7 @@ function resolveDataDir() {
|
|
|
12706
12819
|
// local dev: running from repo root
|
|
12707
12820
|
];
|
|
12708
12821
|
for (const candidate of candidates) {
|
|
12709
|
-
if ((0,
|
|
12822
|
+
if ((0, import_node_fs13.existsSync)((0, import_node_path8.join)(candidate, "skills"))) {
|
|
12710
12823
|
return candidate;
|
|
12711
12824
|
}
|
|
12712
12825
|
}
|
|
@@ -12722,7 +12835,7 @@ function registerInitCommand(program2) {
|
|
|
12722
12835
|
program2.command("init").description("Initialize GATE.md in the current project").option("--force", "Overwrite existing skills and hooks").action(async (opts) => {
|
|
12723
12836
|
const force = opts.force ?? false;
|
|
12724
12837
|
const projectMarkers = [".git", "package.json", "pyproject.toml", "go.mod", "Cargo.toml", "Gemfile", "pom.xml", "build.gradle"];
|
|
12725
|
-
const isProject = projectMarkers.some((m) => (0,
|
|
12838
|
+
const isProject = projectMarkers.some((m) => (0, import_node_fs13.existsSync)(m));
|
|
12726
12839
|
if (!isProject) {
|
|
12727
12840
|
printError("No project detected in the current directory.");
|
|
12728
12841
|
printInfo('Run "gate init" from your project root.');
|
|
@@ -12782,14 +12895,14 @@ function registerInitCommand(program2) {
|
|
|
12782
12895
|
for (const skill of skills) {
|
|
12783
12896
|
const src = (0, import_node_path8.join)(skillsSource, skill);
|
|
12784
12897
|
const dest = (0, import_node_path8.join)(skillsDest, skill);
|
|
12785
|
-
if (!(0,
|
|
12898
|
+
if (!(0, import_node_fs13.existsSync)(src)) {
|
|
12786
12899
|
printWarn(` Skill data not found: ${skill}`);
|
|
12787
12900
|
continue;
|
|
12788
12901
|
}
|
|
12789
|
-
if ((0,
|
|
12902
|
+
if ((0, import_node_fs13.existsSync)(dest) && !force) {
|
|
12790
12903
|
const srcSkill = (0, import_node_path8.join)(src, "SKILL.md");
|
|
12791
12904
|
const destSkill = (0, import_node_path8.join)(dest, "SKILL.md");
|
|
12792
|
-
if ((0,
|
|
12905
|
+
if ((0, import_node_fs13.existsSync)(destSkill)) {
|
|
12793
12906
|
try {
|
|
12794
12907
|
const srcContent = await (0, import_promises8.readFile)(srcSkill, "utf-8");
|
|
12795
12908
|
const destContent = await (0, import_promises8.readFile)(destSkill, "utf-8");
|
|
@@ -12835,7 +12948,7 @@ function registerInitCommand(program2) {
|
|
|
12835
12948
|
}
|
|
12836
12949
|
|
|
12837
12950
|
// src/cli.ts
|
|
12838
|
-
program.name("gate").description("CLI for GATE.md quality gate service").version("0.14.
|
|
12951
|
+
program.name("gate").description("CLI for GATE.md quality gate service").version("0.14.3").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr");
|
|
12839
12952
|
registerAuthCommands(program);
|
|
12840
12953
|
registerHooksCommands(program);
|
|
12841
12954
|
registerIntentCommands(program);
|