@methiu/raigal 1.0.1 → 1.0.2
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/dist/cli.js +551 -367
- package/dist/index.js +38 -9
- package/dist/{json-DBN8fnd3.js → json-C9fBWj3V.js} +1 -1
- package/dist/{json-Be-AUuDb.js → json-CjTR6e4V.js} +1 -1
- package/dist/mcp.js +23 -6
- package/dist/report-pr-closed-CDdQjRWj.js +44 -0
- package/dist/{sarif-B-l1Fhzd.js → sarif--DI_2p2r.js} +1 -1
- package/dist/{sarif-C9k9QYGi.js → sarif-BHrT2Drf.js} +1 -1
- package/dist/{version-om7oAIVO.js → version-DW_ZBtce.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -108,7 +108,28 @@ const getProviderStatuses = () => PROVIDERS.map((provider) => {
|
|
|
108
108
|
};
|
|
109
109
|
});
|
|
110
110
|
const resolveProvider = (selection, statuses = getProviderStatuses()) => {
|
|
111
|
-
if (selection !== "auto")
|
|
111
|
+
if (selection !== "auto") {
|
|
112
|
+
const found = statuses.find((status) => status.provider.id === selection);
|
|
113
|
+
if (found) return found;
|
|
114
|
+
if (commandExists(selection)) return {
|
|
115
|
+
provider: {
|
|
116
|
+
id: selection,
|
|
117
|
+
label: selection,
|
|
118
|
+
bin: selection,
|
|
119
|
+
loginCommand: {
|
|
120
|
+
command: selection,
|
|
121
|
+
args: ["login"]
|
|
122
|
+
},
|
|
123
|
+
loginHint: `Run \`${selection} login\`.`,
|
|
124
|
+
buildArgs: (prompt) => [prompt]
|
|
125
|
+
},
|
|
126
|
+
installed: true,
|
|
127
|
+
authenticated: true,
|
|
128
|
+
version: readVersion(selection),
|
|
129
|
+
authHint: null
|
|
130
|
+
};
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
112
133
|
return statuses.find((status) => status.installed && status.authenticated !== false) ?? statuses.find((status) => status.installed) ?? null;
|
|
113
134
|
};
|
|
114
135
|
//#endregion
|
|
@@ -863,7 +884,7 @@ const createLogger = (deps = {}) => {
|
|
|
863
884
|
const log = createLogger();
|
|
864
885
|
//#endregion
|
|
865
886
|
//#region src/version.ts
|
|
866
|
-
const APP_VERSION = "1.0.
|
|
887
|
+
const APP_VERSION = "1.0.2";
|
|
867
888
|
//#endregion
|
|
868
889
|
//#region src/commands/agent-connect.ts
|
|
869
890
|
const commandText = (status) => [status.provider.loginCommand.command, ...status.provider.loginCommand.args].join(" ");
|
|
@@ -1058,7 +1079,8 @@ const Finding = z.object({
|
|
|
1058
1079
|
severity: Severity,
|
|
1059
1080
|
path: z.string().max(500),
|
|
1060
1081
|
line: z.number().int().nonnegative(),
|
|
1061
|
-
fingerprint: z.string().length(32)
|
|
1082
|
+
fingerprint: z.string().length(32),
|
|
1083
|
+
message: z.string().max(500).optional()
|
|
1062
1084
|
});
|
|
1063
1085
|
const RepoRef = z.object({
|
|
1064
1086
|
provider: z.literal("github"),
|
|
@@ -1073,12 +1095,21 @@ const Step = z.object({
|
|
|
1073
1095
|
ms: z.number().int().nonnegative(),
|
|
1074
1096
|
counts: z.record(z.string(), z.number()).optional()
|
|
1075
1097
|
});
|
|
1098
|
+
const AgentTelemetry = z.object({
|
|
1099
|
+
provider: z.string().max(80),
|
|
1100
|
+
before_score: z.number().min(0).max(100).nullable(),
|
|
1101
|
+
after_score: z.number().min(0).max(100).nullable(),
|
|
1102
|
+
pr_url: z.string().url().max(500).optional(),
|
|
1103
|
+
patch_diff: z.string().max(2e4).optional(),
|
|
1104
|
+
duration_ms: z.number().int().nonnegative().optional()
|
|
1105
|
+
});
|
|
1076
1106
|
const Report = z.object({
|
|
1077
1107
|
score: z.number().min(0).max(100).nullable(),
|
|
1078
1108
|
scoreable: z.boolean(),
|
|
1079
1109
|
engine_scores: z.record(z.string(), z.number()).optional(),
|
|
1080
1110
|
files_scanned: z.number().int().nonnegative(),
|
|
1081
|
-
findings: z.array(Finding).max(5e3)
|
|
1111
|
+
findings: z.array(Finding).max(5e3),
|
|
1112
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
1082
1113
|
});
|
|
1083
1114
|
const Run = z.object({
|
|
1084
1115
|
run_id: z.uuid(),
|
|
@@ -1095,7 +1126,13 @@ const Run = z.object({
|
|
|
1095
1126
|
branch: z.string().max(200).optional(),
|
|
1096
1127
|
head_sha: z.string().max(64).optional(),
|
|
1097
1128
|
base_ref: z.string().max(200).optional(),
|
|
1098
|
-
pr_number: z.number().int().optional()
|
|
1129
|
+
pr_number: z.number().int().optional(),
|
|
1130
|
+
diff_summary: z.object({
|
|
1131
|
+
files_changed: z.number().int().nonnegative(),
|
|
1132
|
+
additions: z.number().int().nonnegative(),
|
|
1133
|
+
deletions: z.number().int().nonnegative()
|
|
1134
|
+
}).optional(),
|
|
1135
|
+
diff_preview: z.string().max(1e4).optional()
|
|
1099
1136
|
}),
|
|
1100
1137
|
ci: z.object({
|
|
1101
1138
|
provider: z.string().max(40),
|
|
@@ -1111,7 +1148,8 @@ const Run = z.object({
|
|
|
1111
1148
|
ended_at: z.iso.datetime(),
|
|
1112
1149
|
exit_code: z.number().int(),
|
|
1113
1150
|
steps: z.array(Step).max(200),
|
|
1114
|
-
report: Report.optional()
|
|
1151
|
+
report: Report.optional(),
|
|
1152
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
1115
1153
|
});
|
|
1116
1154
|
const Policy = z.object({
|
|
1117
1155
|
version: z.number().int(),
|
|
@@ -1345,7 +1383,7 @@ const verifyEntitlementJwt = (jwt, options = {}) => {
|
|
|
1345
1383
|
const claims = parsed.data;
|
|
1346
1384
|
const expectedIssuer = process.env.RAIGAL_ISSUER?.trim() || "https://app.raigal.dev";
|
|
1347
1385
|
if (claims.iss !== expectedIssuer) throw new JwtVerificationError(`Untrusted issuer: ${claims.iss}`, "invalid_issuer");
|
|
1348
|
-
if (!isVersionAtLeast("1.0.
|
|
1386
|
+
if (!isVersionAtLeast("1.0.2", claims.min_cli_version)) throw new JwtVerificationError(`CLI version ${APP_VERSION} is below required minimum ${claims.min_cli_version}. Run "raigal update" or "npm install -g @methiu/raigal@latest".`, "cli_version_unsupported");
|
|
1349
1387
|
const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
1350
1388
|
const grace = options.allowGraceSeconds ?? 0;
|
|
1351
1389
|
if (now > claims.exp + grace) {
|
|
@@ -2575,6 +2613,385 @@ var AgentTui = class {
|
|
|
2575
2613
|
}
|
|
2576
2614
|
};
|
|
2577
2615
|
//#endregion
|
|
2616
|
+
//#region src/cloud/context.ts
|
|
2617
|
+
const execGit = (args, cwd) => {
|
|
2618
|
+
try {
|
|
2619
|
+
const res = spawnSync("git", args, {
|
|
2620
|
+
cwd: path.resolve(cwd),
|
|
2621
|
+
encoding: "utf-8",
|
|
2622
|
+
stdio: [
|
|
2623
|
+
"ignore",
|
|
2624
|
+
"pipe",
|
|
2625
|
+
"ignore"
|
|
2626
|
+
]
|
|
2627
|
+
});
|
|
2628
|
+
if (res.error || res.status !== 0) return void 0;
|
|
2629
|
+
return res.stdout.trim() || void 0;
|
|
2630
|
+
} catch {
|
|
2631
|
+
return;
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
const detectDefaultBranch = (directory) => {
|
|
2635
|
+
try {
|
|
2636
|
+
const out = execGit(["symbolic-ref", "refs/remotes/origin/HEAD"], directory);
|
|
2637
|
+
if (out && out.startsWith("refs/remotes/origin/")) return out.replace("refs/remotes/origin/", "").trim();
|
|
2638
|
+
} catch {}
|
|
2639
|
+
return "main";
|
|
2640
|
+
};
|
|
2641
|
+
const detectGitDiff = (directory, baseRef) => {
|
|
2642
|
+
const targetBase = baseRef || detectDefaultBranch(directory);
|
|
2643
|
+
try {
|
|
2644
|
+
let shortstat = execGit([
|
|
2645
|
+
"diff",
|
|
2646
|
+
"--shortstat",
|
|
2647
|
+
`${targetBase}...HEAD`
|
|
2648
|
+
], directory);
|
|
2649
|
+
if (!shortstat) shortstat = execGit([
|
|
2650
|
+
"diff",
|
|
2651
|
+
"--shortstat",
|
|
2652
|
+
`origin/${targetBase}...HEAD`
|
|
2653
|
+
], directory);
|
|
2654
|
+
if (!shortstat) shortstat = execGit([
|
|
2655
|
+
"diff",
|
|
2656
|
+
"--shortstat",
|
|
2657
|
+
"HEAD~1"
|
|
2658
|
+
], directory);
|
|
2659
|
+
let diffSummary;
|
|
2660
|
+
if (shortstat) {
|
|
2661
|
+
const filesMatch = shortstat.match(/(\d+)\s+files?\s+changed/);
|
|
2662
|
+
const addMatch = shortstat.match(/(\d+)\s+insertions?\s*\(\+\)/);
|
|
2663
|
+
const delMatch = shortstat.match(/(\d+)\s+deletions?\s*\(-\)/);
|
|
2664
|
+
diffSummary = {
|
|
2665
|
+
files_changed: filesMatch ? Number.parseInt(filesMatch[1], 10) : 1,
|
|
2666
|
+
additions: addMatch ? Number.parseInt(addMatch[1], 10) : 0,
|
|
2667
|
+
deletions: delMatch ? Number.parseInt(delMatch[1], 10) : 0
|
|
2668
|
+
};
|
|
2669
|
+
}
|
|
2670
|
+
let preview = execGit([
|
|
2671
|
+
"diff",
|
|
2672
|
+
"-U2",
|
|
2673
|
+
"--no-color",
|
|
2674
|
+
`${targetBase}...HEAD`
|
|
2675
|
+
], directory);
|
|
2676
|
+
if (!preview) preview = execGit([
|
|
2677
|
+
"diff",
|
|
2678
|
+
"-U2",
|
|
2679
|
+
"--no-color",
|
|
2680
|
+
`origin/${targetBase}...HEAD`
|
|
2681
|
+
], directory);
|
|
2682
|
+
if (!preview) preview = execGit([
|
|
2683
|
+
"diff",
|
|
2684
|
+
"-U2",
|
|
2685
|
+
"--no-color",
|
|
2686
|
+
"HEAD~1"
|
|
2687
|
+
], directory);
|
|
2688
|
+
let diffPreview;
|
|
2689
|
+
if (preview) diffPreview = preview.split("\n").slice(0, 40).join("\n").slice(0, 1e4);
|
|
2690
|
+
return {
|
|
2691
|
+
diffSummary,
|
|
2692
|
+
diffPreview
|
|
2693
|
+
};
|
|
2694
|
+
} catch {
|
|
2695
|
+
return {};
|
|
2696
|
+
}
|
|
2697
|
+
};
|
|
2698
|
+
const getRootCommitHash = (directory) => {
|
|
2699
|
+
const hash = execGit([
|
|
2700
|
+
"rev-list",
|
|
2701
|
+
"--max-parents=0",
|
|
2702
|
+
"HEAD"
|
|
2703
|
+
], directory);
|
|
2704
|
+
if (!hash) return void 0;
|
|
2705
|
+
const firstLine = hash.split("\n")[0]?.trim();
|
|
2706
|
+
return firstLine && /^[0-9a-f]{40,64}$/i.test(firstLine) ? firstLine : void 0;
|
|
2707
|
+
};
|
|
2708
|
+
const detectRepoRef = (directory, ownerId) => {
|
|
2709
|
+
const detected = detectLocalRepoOwner(directory);
|
|
2710
|
+
if (!detected.owner || !detected.repo) return null;
|
|
2711
|
+
return {
|
|
2712
|
+
provider: "github",
|
|
2713
|
+
slug: `${detected.owner}/${detected.repo}`.toLowerCase(),
|
|
2714
|
+
owner_id: ownerId,
|
|
2715
|
+
root_commit_hash: getRootCommitHash(directory)
|
|
2716
|
+
};
|
|
2717
|
+
};
|
|
2718
|
+
const readGitHubEventPayload = () => {
|
|
2719
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
2720
|
+
if (!eventPath || !fs.existsSync(eventPath)) return null;
|
|
2721
|
+
try {
|
|
2722
|
+
const content = fs.readFileSync(eventPath, "utf-8");
|
|
2723
|
+
return JSON.parse(content);
|
|
2724
|
+
} catch {
|
|
2725
|
+
return null;
|
|
2726
|
+
}
|
|
2727
|
+
};
|
|
2728
|
+
const detectGitContext = (directory) => {
|
|
2729
|
+
const eventPayload = readGitHubEventPayload();
|
|
2730
|
+
const pr = eventPayload?.pull_request;
|
|
2731
|
+
let headSha = pr?.head?.sha;
|
|
2732
|
+
if (!headSha) headSha = process.env.GITHUB_SHA || execGit(["rev-parse", "HEAD"], directory);
|
|
2733
|
+
let branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME;
|
|
2734
|
+
if (!branch) {
|
|
2735
|
+
branch = execGit([
|
|
2736
|
+
"rev-parse",
|
|
2737
|
+
"--abbrev-ref",
|
|
2738
|
+
"HEAD"
|
|
2739
|
+
], directory);
|
|
2740
|
+
if (branch === "HEAD") branch = void 0;
|
|
2741
|
+
}
|
|
2742
|
+
let baseRef = pr?.base?.ref || process.env.GITHUB_BASE_REF;
|
|
2743
|
+
if (!baseRef) baseRef = void 0;
|
|
2744
|
+
let prNumber;
|
|
2745
|
+
if (typeof pr?.number === "number") prNumber = pr.number;
|
|
2746
|
+
else if (typeof eventPayload?.number === "number") prNumber = eventPayload.number;
|
|
2747
|
+
else if (process.env.GITHUB_REF) {
|
|
2748
|
+
const match = process.env.GITHUB_REF.match(/^refs\/pull\/(\d+)\//);
|
|
2749
|
+
if (match && match[1]) prNumber = Number.parseInt(match[1], 10);
|
|
2750
|
+
}
|
|
2751
|
+
const result = {};
|
|
2752
|
+
if (branch) result.branch = branch;
|
|
2753
|
+
if (headSha) result.head_sha = headSha;
|
|
2754
|
+
if (baseRef) result.base_ref = baseRef;
|
|
2755
|
+
if (prNumber !== void 0 && !Number.isNaN(prNumber)) result.pr_number = prNumber;
|
|
2756
|
+
const { diffSummary, diffPreview } = detectGitDiff(directory, baseRef);
|
|
2757
|
+
if (diffSummary) result.diff_summary = diffSummary;
|
|
2758
|
+
if (diffPreview) result.diff_preview = diffPreview;
|
|
2759
|
+
return result;
|
|
2760
|
+
};
|
|
2761
|
+
const detectCiContext = () => {
|
|
2762
|
+
if (process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1") {
|
|
2763
|
+
const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com";
|
|
2764
|
+
const repo = process.env.GITHUB_REPOSITORY;
|
|
2765
|
+
const runId = process.env.GITHUB_RUN_ID;
|
|
2766
|
+
let runUrl;
|
|
2767
|
+
if (repo && runId) {
|
|
2768
|
+
const attempt = process.env.GITHUB_RUN_ATTEMPT;
|
|
2769
|
+
runUrl = `${serverUrl}/${repo}/actions/runs/${runId}${attempt ? `/attempts/${attempt}` : ""}`;
|
|
2770
|
+
}
|
|
2771
|
+
return {
|
|
2772
|
+
provider: "github-actions",
|
|
2773
|
+
...runUrl ? { run_url: runUrl } : {}
|
|
2774
|
+
};
|
|
2775
|
+
}
|
|
2776
|
+
if (process.env.CI === "true" || process.env.CI === "1") return { provider: process.env.GITLAB_CI && "gitlab-ci" || process.env.BITBUCKET_BUILD_NUMBER && "bitbucket-pipelines" || process.env.CIRCLECI && "circleci" || process.env.BUILDKITE && "buildkite" || process.env.TRAVIS && "travis-ci" || "generic-ci" };
|
|
2777
|
+
};
|
|
2778
|
+
//#endregion
|
|
2779
|
+
//#region src/cloud/outbox.ts
|
|
2780
|
+
const MAX_OUTBOX_BYTES = 5 * 1024 * 1024;
|
|
2781
|
+
const getMaxOutboxBytes = () => {
|
|
2782
|
+
const override = process.env.RAIGAL_MAX_OUTBOX_BYTES;
|
|
2783
|
+
if (override) {
|
|
2784
|
+
const parsed = Number.parseInt(override, 10);
|
|
2785
|
+
if (!Number.isNaN(parsed) && parsed > 0) return parsed;
|
|
2786
|
+
}
|
|
2787
|
+
return MAX_OUTBOX_BYTES;
|
|
2788
|
+
};
|
|
2789
|
+
const loadOutboxRuns = () => {
|
|
2790
|
+
const outboxPath = getOutboxPath();
|
|
2791
|
+
if (!fs.existsSync(outboxPath)) return [];
|
|
2792
|
+
try {
|
|
2793
|
+
const lines = fs.readFileSync(outboxPath, "utf-8").split("\n").filter((l) => l.trim().length > 0);
|
|
2794
|
+
const runs = [];
|
|
2795
|
+
for (const line of lines) try {
|
|
2796
|
+
const parsed = JSON.parse(line);
|
|
2797
|
+
const valid = Run.safeParse(parsed);
|
|
2798
|
+
if (valid.success) runs.push(valid.data);
|
|
2799
|
+
} catch {}
|
|
2800
|
+
return runs;
|
|
2801
|
+
} catch {
|
|
2802
|
+
return [];
|
|
2803
|
+
}
|
|
2804
|
+
};
|
|
2805
|
+
const writeRunsToOutbox = (runs) => {
|
|
2806
|
+
const outboxPath = getOutboxPath();
|
|
2807
|
+
const dir = path.dirname(outboxPath);
|
|
2808
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, {
|
|
2809
|
+
recursive: true,
|
|
2810
|
+
mode: 448
|
|
2811
|
+
});
|
|
2812
|
+
let lines = runs.map((r) => JSON.stringify(r));
|
|
2813
|
+
let text = lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
2814
|
+
const maxBytes = getMaxOutboxBytes();
|
|
2815
|
+
while (Buffer.byteLength(text, "utf-8") > maxBytes && lines.length > 1) {
|
|
2816
|
+
lines.shift();
|
|
2817
|
+
text = `${lines.join("\n")}\n`;
|
|
2818
|
+
}
|
|
2819
|
+
const temp = `${outboxPath}.${Date.now()}.tmp`;
|
|
2820
|
+
fs.writeFileSync(temp, text, { mode: 384 });
|
|
2821
|
+
try {
|
|
2822
|
+
fs.renameSync(temp, outboxPath);
|
|
2823
|
+
} catch {
|
|
2824
|
+
fs.rmSync(temp, { force: true });
|
|
2825
|
+
fs.writeFileSync(outboxPath, text, { mode: 384 });
|
|
2826
|
+
}
|
|
2827
|
+
};
|
|
2828
|
+
const enqueueRun = (run) => {
|
|
2829
|
+
const existing = loadOutboxRuns();
|
|
2830
|
+
existing.push(run);
|
|
2831
|
+
writeRunsToOutbox(existing);
|
|
2832
|
+
};
|
|
2833
|
+
const getLastRecordedRun = () => {
|
|
2834
|
+
const runs = loadOutboxRuns();
|
|
2835
|
+
return runs.length > 0 ? runs[runs.length - 1] ?? null : null;
|
|
2836
|
+
};
|
|
2837
|
+
const flushOutbox = async (token) => {
|
|
2838
|
+
const runs = loadOutboxRuns();
|
|
2839
|
+
if (runs.length === 0) return {
|
|
2840
|
+
sent: 0,
|
|
2841
|
+
failed: 0,
|
|
2842
|
+
remaining: 0
|
|
2843
|
+
};
|
|
2844
|
+
let sentCount = 0;
|
|
2845
|
+
let failCount = 0;
|
|
2846
|
+
const remainingRuns = [];
|
|
2847
|
+
for (let i = 0; i < runs.length; i++) {
|
|
2848
|
+
const run = runs[i];
|
|
2849
|
+
try {
|
|
2850
|
+
await requestApi("/v1/runs", {
|
|
2851
|
+
method: "POST",
|
|
2852
|
+
token,
|
|
2853
|
+
body: run,
|
|
2854
|
+
timeoutMs: 4e3
|
|
2855
|
+
});
|
|
2856
|
+
sentCount++;
|
|
2857
|
+
} catch (err) {
|
|
2858
|
+
if (err instanceof ApiError) {
|
|
2859
|
+
if ([
|
|
2860
|
+
400,
|
|
2861
|
+
401,
|
|
2862
|
+
403,
|
|
2863
|
+
413,
|
|
2864
|
+
422
|
|
2865
|
+
].includes(err.status)) {
|
|
2866
|
+
failCount++;
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2869
|
+
if (err.status === 409) {
|
|
2870
|
+
sentCount++;
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
failCount++;
|
|
2875
|
+
remainingRuns.push(...runs.slice(i));
|
|
2876
|
+
break;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
writeRunsToOutbox(remainingRuns);
|
|
2880
|
+
return {
|
|
2881
|
+
sent: sentCount,
|
|
2882
|
+
failed: failCount,
|
|
2883
|
+
remaining: remainingRuns.length
|
|
2884
|
+
};
|
|
2885
|
+
};
|
|
2886
|
+
//#endregion
|
|
2887
|
+
//#region src/cloud/recorder.ts
|
|
2888
|
+
var CloudRunRecorder = class {
|
|
2889
|
+
runId;
|
|
2890
|
+
command;
|
|
2891
|
+
directory;
|
|
2892
|
+
flags;
|
|
2893
|
+
startedAt;
|
|
2894
|
+
steps = [];
|
|
2895
|
+
report;
|
|
2896
|
+
policyMeta;
|
|
2897
|
+
gitContextOverride;
|
|
2898
|
+
agentTelemetry;
|
|
2899
|
+
seq = 0;
|
|
2900
|
+
finished = false;
|
|
2901
|
+
constructor(command, directory, flags = []) {
|
|
2902
|
+
this.runId = randomUUID();
|
|
2903
|
+
this.command = command;
|
|
2904
|
+
this.directory = directory;
|
|
2905
|
+
this.flags = flags.map((f) => f.replace(/^--?/, "")).filter((f) => f.length > 0).slice(0, 40);
|
|
2906
|
+
this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2907
|
+
}
|
|
2908
|
+
recordStep(name, durationMs, ok = true, counts) {
|
|
2909
|
+
if (this.steps.length >= 200) return;
|
|
2910
|
+
this.steps.push({
|
|
2911
|
+
seq: this.seq++,
|
|
2912
|
+
name: name.slice(0, 80),
|
|
2913
|
+
ok,
|
|
2914
|
+
ms: Math.max(0, Math.round(durationMs)),
|
|
2915
|
+
counts
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
setReport(report) {
|
|
2919
|
+
this.report = report;
|
|
2920
|
+
}
|
|
2921
|
+
setPolicyMeta(version, hash) {
|
|
2922
|
+
this.policyMeta = {
|
|
2923
|
+
version,
|
|
2924
|
+
hash: hash.slice(0, 64)
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
setAgentTelemetry(telemetry) {
|
|
2928
|
+
this.agentTelemetry = telemetry;
|
|
2929
|
+
}
|
|
2930
|
+
setGitContext(git) {
|
|
2931
|
+
this.gitContextOverride = {
|
|
2932
|
+
...this.gitContextOverride,
|
|
2933
|
+
...git
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
buildRunPayload(exitCode) {
|
|
2937
|
+
const repo = detectRepoRef(this.directory) || {
|
|
2938
|
+
provider: "github",
|
|
2939
|
+
slug: "unknown/unknown"
|
|
2940
|
+
};
|
|
2941
|
+
const git = {
|
|
2942
|
+
...detectGitContext(this.directory),
|
|
2943
|
+
...this.gitContextOverride
|
|
2944
|
+
};
|
|
2945
|
+
const ci = detectCiContext();
|
|
2946
|
+
const ownerVerified = Boolean(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);
|
|
2947
|
+
return {
|
|
2948
|
+
run_id: this.runId,
|
|
2949
|
+
command: this.command,
|
|
2950
|
+
repo,
|
|
2951
|
+
owner_verified: ownerVerified,
|
|
2952
|
+
git,
|
|
2953
|
+
ci,
|
|
2954
|
+
flags: this.flags,
|
|
2955
|
+
cli_version: APP_VERSION,
|
|
2956
|
+
policy: this.policyMeta,
|
|
2957
|
+
started_at: this.startedAt,
|
|
2958
|
+
ended_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2959
|
+
exit_code: exitCode,
|
|
2960
|
+
steps: this.steps.slice(0, 200),
|
|
2961
|
+
report: this.report ? {
|
|
2962
|
+
...this.report,
|
|
2963
|
+
agent_telemetry: this.agentTelemetry || this.report.agent_telemetry
|
|
2964
|
+
} : void 0,
|
|
2965
|
+
agent_telemetry: this.agentTelemetry
|
|
2966
|
+
};
|
|
2967
|
+
}
|
|
2968
|
+
async finish(exitCode) {
|
|
2969
|
+
if (this.finished) return;
|
|
2970
|
+
this.finished = true;
|
|
2971
|
+
try {
|
|
2972
|
+
enqueueRun(this.buildRunPayload(exitCode));
|
|
2973
|
+
const activeToken = getActiveToken();
|
|
2974
|
+
if (activeToken) await flushOutbox(activeToken.token);
|
|
2975
|
+
} catch {}
|
|
2976
|
+
}
|
|
2977
|
+
};
|
|
2978
|
+
let activeRecorder = null;
|
|
2979
|
+
const getActiveRecorder = () => activeRecorder;
|
|
2980
|
+
const startRunRecorder = (command, directory, flags = []) => {
|
|
2981
|
+
const recorder = new CloudRunRecorder(command, directory, flags);
|
|
2982
|
+
activeRecorder = recorder;
|
|
2983
|
+
const activeToken = getActiveToken();
|
|
2984
|
+
if (activeToken) flushOutbox(activeToken.token).catch(() => {});
|
|
2985
|
+
return recorder;
|
|
2986
|
+
};
|
|
2987
|
+
const finishActiveRecorder = async (exitCode = 0) => {
|
|
2988
|
+
if (activeRecorder) {
|
|
2989
|
+
const rec = activeRecorder;
|
|
2990
|
+
activeRecorder = null;
|
|
2991
|
+
await rec.finish(exitCode);
|
|
2992
|
+
}
|
|
2993
|
+
};
|
|
2994
|
+
//#endregion
|
|
2578
2995
|
//#region src/commands/agent-local-cli.ts
|
|
2579
2996
|
const cliPath$1 = () => {
|
|
2580
2997
|
const arg = process.argv[1];
|
|
@@ -3466,6 +3883,47 @@ const runAgentSession = async (selected, resolvedDir, options, started) => {
|
|
|
3466
3883
|
published: Boolean(published)
|
|
3467
3884
|
});
|
|
3468
3885
|
await tui.finish({ footer: `Done · ${selected.provider.id} · ${Math.round(performance.now() - started)}ms` });
|
|
3886
|
+
const recorder = getActiveRecorder();
|
|
3887
|
+
if (recorder) {
|
|
3888
|
+
let patchDiff;
|
|
3889
|
+
if (created?.worktree?.path) try {
|
|
3890
|
+
patchDiff = (spawnSync("git", [
|
|
3891
|
+
"diff",
|
|
3892
|
+
"-U2",
|
|
3893
|
+
"--no-color",
|
|
3894
|
+
"HEAD"
|
|
3895
|
+
], {
|
|
3896
|
+
cwd: created.worktree.path,
|
|
3897
|
+
encoding: "utf-8"
|
|
3898
|
+
}).stdout || "").slice(0, 2e4) || void 0;
|
|
3899
|
+
} catch {}
|
|
3900
|
+
if (published) {
|
|
3901
|
+
const prMatch = published.prUrl?.match(/\/pull\/(\d+)/);
|
|
3902
|
+
const prNumber = prMatch ? Number.parseInt(prMatch[1], 10) : void 0;
|
|
3903
|
+
recorder.setGitContext({
|
|
3904
|
+
branch: published.branch,
|
|
3905
|
+
pr_number: prNumber
|
|
3906
|
+
});
|
|
3907
|
+
} else if (options.branch) recorder.setGitContext({ branch: options.branch });
|
|
3908
|
+
const agentTelemetry = {
|
|
3909
|
+
provider: selected.provider.id,
|
|
3910
|
+
before_score: before.score,
|
|
3911
|
+
after_score: verified.after.score,
|
|
3912
|
+
pr_url: published?.prUrl || void 0,
|
|
3913
|
+
patch_diff: patchDiff,
|
|
3914
|
+
duration_ms: Math.round(performance.now() - started)
|
|
3915
|
+
};
|
|
3916
|
+
recorder.setAgentTelemetry(agentTelemetry);
|
|
3917
|
+
recorder.recordStep("agent:baseline", 50, true);
|
|
3918
|
+
recorder.recordStep("agent:verify", Math.round(performance.now() - started), verified.after.score !== null && verified.after.score >= options.targetScore);
|
|
3919
|
+
recorder.setReport({
|
|
3920
|
+
score: verified.after.score,
|
|
3921
|
+
scoreable: true,
|
|
3922
|
+
files_scanned: changedFiles.length,
|
|
3923
|
+
findings: [],
|
|
3924
|
+
agent_telemetry: agentTelemetry
|
|
3925
|
+
});
|
|
3926
|
+
}
|
|
3469
3927
|
printAgentSessionSummary({
|
|
3470
3928
|
before,
|
|
3471
3929
|
after: verified.after,
|
|
@@ -7175,178 +7633,70 @@ const pollDeviceAuthorization = async (grant) => {
|
|
|
7175
7633
|
try {
|
|
7176
7634
|
const pollResult = await pollDeviceToken(grant.device_code);
|
|
7177
7635
|
if (pollResult.status === "pending") continue;
|
|
7178
|
-
if (pollResult.status === "slow_down") {
|
|
7179
|
-
pollIntervalMs += 5e3;
|
|
7180
|
-
continue;
|
|
7181
|
-
}
|
|
7182
|
-
if (pollResult.status === "denied") {
|
|
7183
|
-
log.error(`Login authorization denied: ${pollResult.error ?? "User rejected request."}`);
|
|
7184
|
-
process.exitCode = 1;
|
|
7185
|
-
return;
|
|
7186
|
-
}
|
|
7187
|
-
if (pollResult.status === "expired") {
|
|
7188
|
-
log.error("Login authorization code expired. Please try running `raigal login` again.");
|
|
7189
|
-
process.exitCode = 1;
|
|
7190
|
-
return;
|
|
7191
|
-
}
|
|
7192
|
-
if (pollResult.status === "ok" && pollResult.data) {
|
|
7193
|
-
const { access_token, org, user, expires_at } = pollResult.data;
|
|
7194
|
-
saveStoredCredentials({
|
|
7195
|
-
token: access_token,
|
|
7196
|
-
org,
|
|
7197
|
-
user,
|
|
7198
|
-
expires_at
|
|
7199
|
-
});
|
|
7200
|
-
process.stdout.write("\n");
|
|
7201
|
-
log.success(`Signed in as ${user.email} · ${org.name}`);
|
|
7202
|
-
return;
|
|
7203
|
-
}
|
|
7204
|
-
} catch (err) {
|
|
7205
|
-
log.error(`Polling error: ${err instanceof Error ? err.message : String(err)}`);
|
|
7206
|
-
process.exitCode = 1;
|
|
7207
|
-
return;
|
|
7208
|
-
}
|
|
7209
|
-
}
|
|
7210
|
-
log.error("Login timed out. Please run `raigal login` again.");
|
|
7211
|
-
process.exitCode = 1;
|
|
7212
|
-
};
|
|
7213
|
-
const loginCommand = async (options = {}) => {
|
|
7214
|
-
if (options.withToken) {
|
|
7215
|
-
await loginWithToken();
|
|
7216
|
-
return;
|
|
7217
|
-
}
|
|
7218
|
-
log.info("Starting browser login...");
|
|
7219
|
-
let grant;
|
|
7220
|
-
try {
|
|
7221
|
-
grant = await startDeviceLogin();
|
|
7222
|
-
} catch (err) {
|
|
7223
|
-
log.error(`Failed to start login: ${err instanceof Error ? err.message : String(err)}`);
|
|
7224
|
-
process.exitCode = 1;
|
|
7225
|
-
return;
|
|
7226
|
-
}
|
|
7227
|
-
process.stdout.write("\n");
|
|
7228
|
-
process.stdout.write(` Confirmation code: ${grant.user_code}\n`);
|
|
7229
|
-
process.stdout.write(` Verification URL: ${grant.verification_uri_complete}\n\n`);
|
|
7230
|
-
log.muted("Opening browser to confirm authorization...");
|
|
7231
|
-
openBrowser(grant.verification_uri_complete);
|
|
7232
|
-
await pollDeviceAuthorization(grant);
|
|
7233
|
-
};
|
|
7234
|
-
//#endregion
|
|
7235
|
-
//#region src/commands/logout.ts
|
|
7236
|
-
const logoutCommand = async () => {
|
|
7237
|
-
const active = getActiveToken();
|
|
7238
|
-
if (active && active.kind === "session") await revokeSessionApi(active.token);
|
|
7239
|
-
clearStoredCredentials();
|
|
7240
|
-
clearCachedEntitlement();
|
|
7241
|
-
log.success("Signed out and cleared cached credentials.");
|
|
7242
|
-
};
|
|
7243
|
-
//#endregion
|
|
7244
|
-
//#region src/cloud/outbox.ts
|
|
7245
|
-
const MAX_OUTBOX_BYTES = 5 * 1024 * 1024;
|
|
7246
|
-
const getMaxOutboxBytes = () => {
|
|
7247
|
-
const override = process.env.RAIGAL_MAX_OUTBOX_BYTES;
|
|
7248
|
-
if (override) {
|
|
7249
|
-
const parsed = Number.parseInt(override, 10);
|
|
7250
|
-
if (!Number.isNaN(parsed) && parsed > 0) return parsed;
|
|
7251
|
-
}
|
|
7252
|
-
return MAX_OUTBOX_BYTES;
|
|
7253
|
-
};
|
|
7254
|
-
const loadOutboxRuns = () => {
|
|
7255
|
-
const outboxPath = getOutboxPath();
|
|
7256
|
-
if (!fs.existsSync(outboxPath)) return [];
|
|
7257
|
-
try {
|
|
7258
|
-
const lines = fs.readFileSync(outboxPath, "utf-8").split("\n").filter((l) => l.trim().length > 0);
|
|
7259
|
-
const runs = [];
|
|
7260
|
-
for (const line of lines) try {
|
|
7261
|
-
const parsed = JSON.parse(line);
|
|
7262
|
-
const valid = Run.safeParse(parsed);
|
|
7263
|
-
if (valid.success) runs.push(valid.data);
|
|
7264
|
-
} catch {}
|
|
7265
|
-
return runs;
|
|
7266
|
-
} catch {
|
|
7267
|
-
return [];
|
|
7268
|
-
}
|
|
7269
|
-
};
|
|
7270
|
-
const writeRunsToOutbox = (runs) => {
|
|
7271
|
-
const outboxPath = getOutboxPath();
|
|
7272
|
-
const dir = path.dirname(outboxPath);
|
|
7273
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, {
|
|
7274
|
-
recursive: true,
|
|
7275
|
-
mode: 448
|
|
7276
|
-
});
|
|
7277
|
-
let lines = runs.map((r) => JSON.stringify(r));
|
|
7278
|
-
let text = lines.length > 0 ? `${lines.join("\n")}\n` : "";
|
|
7279
|
-
const maxBytes = getMaxOutboxBytes();
|
|
7280
|
-
while (Buffer.byteLength(text, "utf-8") > maxBytes && lines.length > 1) {
|
|
7281
|
-
lines.shift();
|
|
7282
|
-
text = `${lines.join("\n")}\n`;
|
|
7283
|
-
}
|
|
7284
|
-
const temp = `${outboxPath}.${Date.now()}.tmp`;
|
|
7285
|
-
fs.writeFileSync(temp, text, { mode: 384 });
|
|
7286
|
-
try {
|
|
7287
|
-
fs.renameSync(temp, outboxPath);
|
|
7288
|
-
} catch {
|
|
7289
|
-
fs.rmSync(temp, { force: true });
|
|
7290
|
-
fs.writeFileSync(outboxPath, text, { mode: 384 });
|
|
7291
|
-
}
|
|
7292
|
-
};
|
|
7293
|
-
const enqueueRun = (run) => {
|
|
7294
|
-
const existing = loadOutboxRuns();
|
|
7295
|
-
existing.push(run);
|
|
7296
|
-
writeRunsToOutbox(existing);
|
|
7297
|
-
};
|
|
7298
|
-
const getLastRecordedRun = () => {
|
|
7299
|
-
const runs = loadOutboxRuns();
|
|
7300
|
-
return runs.length > 0 ? runs[runs.length - 1] ?? null : null;
|
|
7301
|
-
};
|
|
7302
|
-
const flushOutbox = async (token) => {
|
|
7303
|
-
const runs = loadOutboxRuns();
|
|
7304
|
-
if (runs.length === 0) return {
|
|
7305
|
-
sent: 0,
|
|
7306
|
-
failed: 0,
|
|
7307
|
-
remaining: 0
|
|
7308
|
-
};
|
|
7309
|
-
let sentCount = 0;
|
|
7310
|
-
let failCount = 0;
|
|
7311
|
-
const remainingRuns = [];
|
|
7312
|
-
for (let i = 0; i < runs.length; i++) {
|
|
7313
|
-
const run = runs[i];
|
|
7314
|
-
try {
|
|
7315
|
-
await requestApi("/v1/runs", {
|
|
7316
|
-
method: "POST",
|
|
7317
|
-
token,
|
|
7318
|
-
body: run,
|
|
7319
|
-
timeoutMs: 4e3
|
|
7320
|
-
});
|
|
7321
|
-
sentCount++;
|
|
7322
|
-
} catch (err) {
|
|
7323
|
-
if (err instanceof ApiError) {
|
|
7324
|
-
if ([
|
|
7325
|
-
400,
|
|
7326
|
-
401,
|
|
7327
|
-
403,
|
|
7328
|
-
413,
|
|
7329
|
-
422
|
|
7330
|
-
].includes(err.status)) {
|
|
7331
|
-
failCount++;
|
|
7332
|
-
continue;
|
|
7333
|
-
}
|
|
7334
|
-
if (err.status === 409) {
|
|
7335
|
-
sentCount++;
|
|
7336
|
-
continue;
|
|
7337
|
-
}
|
|
7636
|
+
if (pollResult.status === "slow_down") {
|
|
7637
|
+
pollIntervalMs += 5e3;
|
|
7638
|
+
continue;
|
|
7338
7639
|
}
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7640
|
+
if (pollResult.status === "denied") {
|
|
7641
|
+
log.error(`Login authorization denied: ${pollResult.error ?? "User rejected request."}`);
|
|
7642
|
+
process.exitCode = 1;
|
|
7643
|
+
return;
|
|
7644
|
+
}
|
|
7645
|
+
if (pollResult.status === "expired") {
|
|
7646
|
+
log.error("Login authorization code expired. Please try running `raigal login` again.");
|
|
7647
|
+
process.exitCode = 1;
|
|
7648
|
+
return;
|
|
7649
|
+
}
|
|
7650
|
+
if (pollResult.status === "ok" && pollResult.data) {
|
|
7651
|
+
const { access_token, org, user, expires_at } = pollResult.data;
|
|
7652
|
+
saveStoredCredentials({
|
|
7653
|
+
token: access_token,
|
|
7654
|
+
org,
|
|
7655
|
+
user,
|
|
7656
|
+
expires_at
|
|
7657
|
+
});
|
|
7658
|
+
process.stdout.write("\n");
|
|
7659
|
+
log.success(`Signed in as ${user.email} · ${org.name}`);
|
|
7660
|
+
return;
|
|
7661
|
+
}
|
|
7662
|
+
} catch (err) {
|
|
7663
|
+
log.error(`Polling error: ${err instanceof Error ? err.message : String(err)}`);
|
|
7664
|
+
process.exitCode = 1;
|
|
7665
|
+
return;
|
|
7342
7666
|
}
|
|
7343
7667
|
}
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7668
|
+
log.error("Login timed out. Please run `raigal login` again.");
|
|
7669
|
+
process.exitCode = 1;
|
|
7670
|
+
};
|
|
7671
|
+
const loginCommand = async (options = {}) => {
|
|
7672
|
+
if (options.withToken) {
|
|
7673
|
+
await loginWithToken();
|
|
7674
|
+
return;
|
|
7675
|
+
}
|
|
7676
|
+
log.info("Starting browser login...");
|
|
7677
|
+
let grant;
|
|
7678
|
+
try {
|
|
7679
|
+
grant = await startDeviceLogin();
|
|
7680
|
+
} catch (err) {
|
|
7681
|
+
log.error(`Failed to start login: ${err instanceof Error ? err.message : String(err)}`);
|
|
7682
|
+
process.exitCode = 1;
|
|
7683
|
+
return;
|
|
7684
|
+
}
|
|
7685
|
+
process.stdout.write("\n");
|
|
7686
|
+
process.stdout.write(` Confirmation code: ${grant.user_code}\n`);
|
|
7687
|
+
process.stdout.write(` Verification URL: ${grant.verification_uri_complete}\n\n`);
|
|
7688
|
+
log.muted("Opening browser to confirm authorization...");
|
|
7689
|
+
openBrowser(grant.verification_uri_complete);
|
|
7690
|
+
await pollDeviceAuthorization(grant);
|
|
7691
|
+
};
|
|
7692
|
+
//#endregion
|
|
7693
|
+
//#region src/commands/logout.ts
|
|
7694
|
+
const logoutCommand = async () => {
|
|
7695
|
+
const active = getActiveToken();
|
|
7696
|
+
if (active && active.kind === "session") await revokeSessionApi(active.token);
|
|
7697
|
+
clearStoredCredentials();
|
|
7698
|
+
clearCachedEntitlement();
|
|
7699
|
+
log.success("Signed out and cleared cached credentials.");
|
|
7350
7700
|
};
|
|
7351
7701
|
//#endregion
|
|
7352
7702
|
//#region src/commands/telemetry-show.ts
|
|
@@ -7450,6 +7800,14 @@ const registerCloudCommands = (program) => {
|
|
|
7450
7800
|
if (flags.show || isJson) await telemetryShowCommand({ json: isJson });
|
|
7451
7801
|
else process.stdout.write("Run `raigal telemetry --show` to inspect recorded telemetry payloads.\n");
|
|
7452
7802
|
});
|
|
7803
|
+
program.command("report-pr-closed").description("Report a pull request closed/merged event to Raigal Cloud").option("--pr <number>", "PR number (default: read from GITHUB_EVENT_PATH)").option("--merged", "Flag indicating whether PR was merged").action(async (flags) => {
|
|
7804
|
+
const prNumber = flags.pr ? Number.parseInt(flags.pr, 10) : void 0;
|
|
7805
|
+
const { reportPrClosedCommand } = await import("./report-pr-closed-CDdQjRWj.js");
|
|
7806
|
+
await reportPrClosedCommand({
|
|
7807
|
+
prNumber,
|
|
7808
|
+
merged: Boolean(flags.merged)
|
|
7809
|
+
});
|
|
7810
|
+
});
|
|
7453
7811
|
};
|
|
7454
7812
|
//#endregion
|
|
7455
7813
|
//#region src/hooks/feedback.ts
|
|
@@ -23984,7 +24342,7 @@ const maybeNotifyUpdate = async (now = Date.now()) => {
|
|
|
23984
24342
|
if (!process.stderr.isTTY) return;
|
|
23985
24343
|
const cachePath = resolveUpdateCachePath();
|
|
23986
24344
|
const cache = readCache(cachePath);
|
|
23987
|
-
if (cache && isOutdated("1.0.
|
|
24345
|
+
if (cache && isOutdated("1.0.2", cache.latest)) process.stderr.write(formatUpdateNotice(APP_VERSION, cache.latest));
|
|
23988
24346
|
if (!cache || now - cache.checkedAt > CHECK_INTERVAL_MS) {
|
|
23989
24347
|
const latest = await fetchLatestVersion$1();
|
|
23990
24348
|
if (latest) writeCache(cachePath, {
|
|
@@ -24504,7 +24862,7 @@ const renderCommandGroup = (group, commandWidth) => {
|
|
|
24504
24862
|
return lines;
|
|
24505
24863
|
};
|
|
24506
24864
|
const renderCommandReference = (input = {}) => {
|
|
24507
|
-
const version = input.version ?? "1.0.
|
|
24865
|
+
const version = input.version ?? "1.0.2";
|
|
24508
24866
|
const commandWidth = Math.max(...COMMAND_REFERENCE.map((item) => item.command.length));
|
|
24509
24867
|
const lines = [renderHeader({
|
|
24510
24868
|
version,
|
|
@@ -24727,7 +25085,7 @@ const renderHelpDetails = () => [
|
|
|
24727
25085
|
].map((line) => highlightRaigal(line, theme)).join("\n");
|
|
24728
25086
|
const renderHome = (input = {}) => {
|
|
24729
25087
|
let out = renderHeader({
|
|
24730
|
-
version: input.version ?? "1.0.
|
|
25088
|
+
version: input.version ?? "1.0.2",
|
|
24731
25089
|
command: "--bare",
|
|
24732
25090
|
context: []
|
|
24733
25091
|
});
|
|
@@ -24885,100 +25243,15 @@ const matchFixAgent = (flags) => {
|
|
|
24885
25243
|
return FIX_AGENT_FLAGS.find((a) => flags[a.name])?.flag;
|
|
24886
25244
|
};
|
|
24887
25245
|
//#endregion
|
|
24888
|
-
//#region src/
|
|
24889
|
-
|
|
24890
|
-
|
|
24891
|
-
|
|
24892
|
-
|
|
24893
|
-
|
|
24894
|
-
|
|
24895
|
-
|
|
24896
|
-
|
|
24897
|
-
"ignore"
|
|
24898
|
-
]
|
|
24899
|
-
});
|
|
24900
|
-
if (res.error || res.status !== 0) return void 0;
|
|
24901
|
-
return res.stdout.trim() || void 0;
|
|
24902
|
-
} catch {
|
|
24903
|
-
return;
|
|
24904
|
-
}
|
|
24905
|
-
};
|
|
24906
|
-
const getRootCommitHash = (directory) => {
|
|
24907
|
-
const hash = execGit([
|
|
24908
|
-
"rev-list",
|
|
24909
|
-
"--max-parents=0",
|
|
24910
|
-
"HEAD"
|
|
24911
|
-
], directory);
|
|
24912
|
-
if (!hash) return void 0;
|
|
24913
|
-
const firstLine = hash.split("\n")[0]?.trim();
|
|
24914
|
-
return firstLine && /^[0-9a-f]{40,64}$/i.test(firstLine) ? firstLine : void 0;
|
|
24915
|
-
};
|
|
24916
|
-
const detectRepoRef = (directory, ownerId) => {
|
|
24917
|
-
const detected = detectLocalRepoOwner(directory);
|
|
24918
|
-
if (!detected.owner || !detected.repo) return null;
|
|
24919
|
-
return {
|
|
24920
|
-
provider: "github",
|
|
24921
|
-
slug: `${detected.owner}/${detected.repo}`.toLowerCase(),
|
|
24922
|
-
owner_id: ownerId,
|
|
24923
|
-
root_commit_hash: getRootCommitHash(directory)
|
|
24924
|
-
};
|
|
24925
|
-
};
|
|
24926
|
-
const readGitHubEventPayload = () => {
|
|
24927
|
-
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
24928
|
-
if (!eventPath || !fs.existsSync(eventPath)) return null;
|
|
24929
|
-
try {
|
|
24930
|
-
const content = fs.readFileSync(eventPath, "utf-8");
|
|
24931
|
-
return JSON.parse(content);
|
|
24932
|
-
} catch {
|
|
24933
|
-
return null;
|
|
24934
|
-
}
|
|
24935
|
-
};
|
|
24936
|
-
const detectGitContext = (directory) => {
|
|
24937
|
-
const eventPayload = readGitHubEventPayload();
|
|
24938
|
-
const pr = eventPayload?.pull_request;
|
|
24939
|
-
let headSha = pr?.head?.sha;
|
|
24940
|
-
if (!headSha) headSha = process.env.GITHUB_SHA || execGit(["rev-parse", "HEAD"], directory);
|
|
24941
|
-
let branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME;
|
|
24942
|
-
if (!branch) {
|
|
24943
|
-
branch = execGit([
|
|
24944
|
-
"rev-parse",
|
|
24945
|
-
"--abbrev-ref",
|
|
24946
|
-
"HEAD"
|
|
24947
|
-
], directory);
|
|
24948
|
-
if (branch === "HEAD") branch = void 0;
|
|
24949
|
-
}
|
|
24950
|
-
let baseRef = pr?.base?.ref || process.env.GITHUB_BASE_REF;
|
|
24951
|
-
if (!baseRef) baseRef = void 0;
|
|
24952
|
-
let prNumber;
|
|
24953
|
-
if (typeof pr?.number === "number") prNumber = pr.number;
|
|
24954
|
-
else if (typeof eventPayload?.number === "number") prNumber = eventPayload.number;
|
|
24955
|
-
else if (process.env.GITHUB_REF) {
|
|
24956
|
-
const match = process.env.GITHUB_REF.match(/^refs\/pull\/(\d+)\//);
|
|
24957
|
-
if (match && match[1]) prNumber = Number.parseInt(match[1], 10);
|
|
24958
|
-
}
|
|
24959
|
-
const result = {};
|
|
24960
|
-
if (branch) result.branch = branch;
|
|
24961
|
-
if (headSha) result.head_sha = headSha;
|
|
24962
|
-
if (baseRef) result.base_ref = baseRef;
|
|
24963
|
-
if (prNumber !== void 0 && !Number.isNaN(prNumber)) result.pr_number = prNumber;
|
|
24964
|
-
return result;
|
|
24965
|
-
};
|
|
24966
|
-
const detectCiContext = () => {
|
|
24967
|
-
if (process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1") {
|
|
24968
|
-
const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com";
|
|
24969
|
-
const repo = process.env.GITHUB_REPOSITORY;
|
|
24970
|
-
const runId = process.env.GITHUB_RUN_ID;
|
|
24971
|
-
let runUrl;
|
|
24972
|
-
if (repo && runId) {
|
|
24973
|
-
const attempt = process.env.GITHUB_RUN_ATTEMPT;
|
|
24974
|
-
runUrl = `${serverUrl}/${repo}/actions/runs/${runId}${attempt ? `/attempts/${attempt}` : ""}`;
|
|
24975
|
-
}
|
|
24976
|
-
return {
|
|
24977
|
-
provider: "github-actions",
|
|
24978
|
-
...runUrl ? { run_url: runUrl } : {}
|
|
24979
|
-
};
|
|
24980
|
-
}
|
|
24981
|
-
if (process.env.CI === "true" || process.env.CI === "1") return { provider: process.env.GITLAB_CI && "gitlab-ci" || process.env.BITBUCKET_BUILD_NUMBER && "bitbucket-pipelines" || process.env.CIRCLECI && "circleci" || process.env.BUILDKITE && "buildkite" || process.env.TRAVIS && "travis-ci" || "generic-ci" };
|
|
25246
|
+
//#region src/output/rule-message.ts
|
|
25247
|
+
/**
|
|
25248
|
+
* Pure deterministic formatter for diagnostic messages.
|
|
25249
|
+
* Secret-class rules (or redactSource: true) unconditionally return FIXED_SECRET_DIAGNOSTIC_MESSAGE.
|
|
25250
|
+
* Non-secret rules return diagnostic.message (clamped to max 500 chars).
|
|
25251
|
+
*/
|
|
25252
|
+
const formatFindingMessage = (diagnostic) => {
|
|
25253
|
+
if (diagnostic.redactSource || isSecretClassRule(diagnostic.rule)) return FIXED_SECRET_DIAGNOSTIC_MESSAGE;
|
|
25254
|
+
return diagnostic.message.slice(0, 500);
|
|
24982
25255
|
};
|
|
24983
25256
|
//#endregion
|
|
24984
25257
|
//#region src/cloud/fingerprint.ts
|
|
@@ -25020,7 +25293,8 @@ const toContractFinding = (diagnostic, rootDirectory, lineTextOverride) => {
|
|
|
25020
25293
|
severity,
|
|
25021
25294
|
path: relativePath,
|
|
25022
25295
|
line: Math.max(0, diagnostic.line),
|
|
25023
|
-
fingerprint
|
|
25296
|
+
fingerprint,
|
|
25297
|
+
message: formatFindingMessage(diagnostic)
|
|
25024
25298
|
};
|
|
25025
25299
|
};
|
|
25026
25300
|
//#endregion
|
|
@@ -25111,96 +25385,6 @@ const applyPolicyToConfig = (localConfig, policy) => {
|
|
|
25111
25385
|
};
|
|
25112
25386
|
};
|
|
25113
25387
|
//#endregion
|
|
25114
|
-
//#region src/cloud/recorder.ts
|
|
25115
|
-
var CloudRunRecorder = class {
|
|
25116
|
-
runId;
|
|
25117
|
-
command;
|
|
25118
|
-
directory;
|
|
25119
|
-
flags;
|
|
25120
|
-
startedAt;
|
|
25121
|
-
steps = [];
|
|
25122
|
-
report;
|
|
25123
|
-
policyMeta;
|
|
25124
|
-
seq = 0;
|
|
25125
|
-
finished = false;
|
|
25126
|
-
constructor(command, directory, flags = []) {
|
|
25127
|
-
this.runId = randomUUID();
|
|
25128
|
-
this.command = command;
|
|
25129
|
-
this.directory = directory;
|
|
25130
|
-
this.flags = flags.map((f) => f.replace(/^--?/, "")).filter((f) => f.length > 0).slice(0, 40);
|
|
25131
|
-
this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
25132
|
-
}
|
|
25133
|
-
recordStep(name, durationMs, ok = true, counts) {
|
|
25134
|
-
if (this.steps.length >= 200) return;
|
|
25135
|
-
this.steps.push({
|
|
25136
|
-
seq: this.seq++,
|
|
25137
|
-
name: name.slice(0, 80),
|
|
25138
|
-
ok,
|
|
25139
|
-
ms: Math.max(0, Math.round(durationMs)),
|
|
25140
|
-
counts
|
|
25141
|
-
});
|
|
25142
|
-
}
|
|
25143
|
-
setReport(report) {
|
|
25144
|
-
this.report = report;
|
|
25145
|
-
}
|
|
25146
|
-
setPolicyMeta(version, hash) {
|
|
25147
|
-
this.policyMeta = {
|
|
25148
|
-
version,
|
|
25149
|
-
hash: hash.slice(0, 64)
|
|
25150
|
-
};
|
|
25151
|
-
}
|
|
25152
|
-
buildRunPayload(exitCode) {
|
|
25153
|
-
const repo = detectRepoRef(this.directory) || {
|
|
25154
|
-
provider: "github",
|
|
25155
|
-
slug: "unknown/unknown"
|
|
25156
|
-
};
|
|
25157
|
-
const git = detectGitContext(this.directory);
|
|
25158
|
-
const ci = detectCiContext();
|
|
25159
|
-
const ownerVerified = Boolean(process.env.ACTIONS_ID_TOKEN_REQUEST_URL);
|
|
25160
|
-
return {
|
|
25161
|
-
run_id: this.runId,
|
|
25162
|
-
command: this.command,
|
|
25163
|
-
repo,
|
|
25164
|
-
owner_verified: ownerVerified,
|
|
25165
|
-
git,
|
|
25166
|
-
ci,
|
|
25167
|
-
flags: this.flags,
|
|
25168
|
-
cli_version: APP_VERSION,
|
|
25169
|
-
policy: this.policyMeta,
|
|
25170
|
-
started_at: this.startedAt,
|
|
25171
|
-
ended_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25172
|
-
exit_code: exitCode,
|
|
25173
|
-
steps: this.steps.slice(0, 200),
|
|
25174
|
-
report: this.report
|
|
25175
|
-
};
|
|
25176
|
-
}
|
|
25177
|
-
async finish(exitCode) {
|
|
25178
|
-
if (this.finished) return;
|
|
25179
|
-
this.finished = true;
|
|
25180
|
-
try {
|
|
25181
|
-
enqueueRun(this.buildRunPayload(exitCode));
|
|
25182
|
-
const activeToken = getActiveToken();
|
|
25183
|
-
if (activeToken) await flushOutbox(activeToken.token);
|
|
25184
|
-
} catch {}
|
|
25185
|
-
}
|
|
25186
|
-
};
|
|
25187
|
-
let activeRecorder = null;
|
|
25188
|
-
const getActiveRecorder = () => activeRecorder;
|
|
25189
|
-
const startRunRecorder = (command, directory, flags = []) => {
|
|
25190
|
-
const recorder = new CloudRunRecorder(command, directory, flags);
|
|
25191
|
-
activeRecorder = recorder;
|
|
25192
|
-
const activeToken = getActiveToken();
|
|
25193
|
-
if (activeToken) flushOutbox(activeToken.token).catch(() => {});
|
|
25194
|
-
return recorder;
|
|
25195
|
-
};
|
|
25196
|
-
const finishActiveRecorder = async (exitCode = 0) => {
|
|
25197
|
-
if (activeRecorder) {
|
|
25198
|
-
const rec = activeRecorder;
|
|
25199
|
-
activeRecorder = null;
|
|
25200
|
-
await rec.finish(exitCode);
|
|
25201
|
-
}
|
|
25202
|
-
};
|
|
25203
|
-
//#endregion
|
|
25204
25388
|
//#region src/engagement/pilot-invitation.ts
|
|
25205
25389
|
const STATE_BASENAME = "pilot_invitation.scans";
|
|
25206
25390
|
const INVITATION_SCAN_THRESHOLD = 3;
|
|
@@ -26435,12 +26619,12 @@ const runScanBody = async (resolvedDir, config, options, projectInfo, scanScope,
|
|
|
26435
26619
|
scoreFileCount
|
|
26436
26620
|
});
|
|
26437
26621
|
if (options.sarif) {
|
|
26438
|
-
const { buildSarifLog } = await import("./sarif
|
|
26622
|
+
const { buildSarifLog } = await import("./sarif--DI_2p2r.js");
|
|
26439
26623
|
console.log(JSON.stringify(buildSarifLog(results), null, 2));
|
|
26440
26624
|
return completion;
|
|
26441
26625
|
}
|
|
26442
26626
|
if (options.json) {
|
|
26443
|
-
const { buildJsonOutput } = await import("./json-
|
|
26627
|
+
const { buildJsonOutput } = await import("./json-C9fBWj3V.js");
|
|
26444
26628
|
const jsonOut = buildJsonOutput(results, scoreResult, scoreFileCount, elapsedMs, scanCoverage);
|
|
26445
26629
|
console.log(JSON.stringify(jsonOut, null, 2));
|
|
26446
26630
|
return completion;
|
|
@@ -29551,4 +29735,4 @@ const main = async () => {
|
|
|
29551
29735
|
};
|
|
29552
29736
|
main();
|
|
29553
29737
|
//#endregion
|
|
29554
|
-
export {
|
|
29738
|
+
export { requestApi as a, log as c, detectRepoRef as i, FIXED_SECRET_DIAGNOSTIC_MESSAGE as l, withFindingAssessments as n, getActiveToken as o, ENGINE_INFO as r, APP_VERSION as s, summarizeFindingAssessments as t, isSecretClassRule as u };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as APP_VERSION } from "./version-
|
|
1
|
+
import { t as APP_VERSION } from "./version-DW_ZBtce.js";
|
|
2
2
|
import { a as getEngineLabel, i as ENGINE_INFO, r as scoreImpactForRule, t as summarizeFindingAssessments } from "./finding-assessment-M5fUTE-C.js";
|
|
3
3
|
import { n as isSecretClassRule, r as maskSecrets, t as FIXED_SECRET_DIAGNOSTIC_MESSAGE } from "./mask-secrets-BXn-ZSEh.js";
|
|
4
4
|
import { createRequire, isBuiltin } from "node:module";
|
|
@@ -15803,7 +15803,8 @@ const Finding = z.object({
|
|
|
15803
15803
|
severity: Severity,
|
|
15804
15804
|
path: z.string().max(500),
|
|
15805
15805
|
line: z.number().int().nonnegative(),
|
|
15806
|
-
fingerprint: z.string().length(32)
|
|
15806
|
+
fingerprint: z.string().length(32),
|
|
15807
|
+
message: z.string().max(500).optional()
|
|
15807
15808
|
});
|
|
15808
15809
|
const RepoRef = z.object({
|
|
15809
15810
|
provider: z.literal("github"),
|
|
@@ -15818,12 +15819,21 @@ const Step = z.object({
|
|
|
15818
15819
|
ms: z.number().int().nonnegative(),
|
|
15819
15820
|
counts: z.record(z.string(), z.number()).optional()
|
|
15820
15821
|
});
|
|
15822
|
+
const AgentTelemetry = z.object({
|
|
15823
|
+
provider: z.string().max(80),
|
|
15824
|
+
before_score: z.number().min(0).max(100).nullable(),
|
|
15825
|
+
after_score: z.number().min(0).max(100).nullable(),
|
|
15826
|
+
pr_url: z.string().url().max(500).optional(),
|
|
15827
|
+
patch_diff: z.string().max(2e4).optional(),
|
|
15828
|
+
duration_ms: z.number().int().nonnegative().optional()
|
|
15829
|
+
});
|
|
15821
15830
|
const Report = z.object({
|
|
15822
15831
|
score: z.number().min(0).max(100).nullable(),
|
|
15823
15832
|
scoreable: z.boolean(),
|
|
15824
15833
|
engine_scores: z.record(z.string(), z.number()).optional(),
|
|
15825
15834
|
files_scanned: z.number().int().nonnegative(),
|
|
15826
|
-
findings: z.array(Finding).max(5e3)
|
|
15835
|
+
findings: z.array(Finding).max(5e3),
|
|
15836
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
15827
15837
|
});
|
|
15828
15838
|
z.object({
|
|
15829
15839
|
run_id: z.uuid(),
|
|
@@ -15840,7 +15850,13 @@ z.object({
|
|
|
15840
15850
|
branch: z.string().max(200).optional(),
|
|
15841
15851
|
head_sha: z.string().max(64).optional(),
|
|
15842
15852
|
base_ref: z.string().max(200).optional(),
|
|
15843
|
-
pr_number: z.number().int().optional()
|
|
15853
|
+
pr_number: z.number().int().optional(),
|
|
15854
|
+
diff_summary: z.object({
|
|
15855
|
+
files_changed: z.number().int().nonnegative(),
|
|
15856
|
+
additions: z.number().int().nonnegative(),
|
|
15857
|
+
deletions: z.number().int().nonnegative()
|
|
15858
|
+
}).optional(),
|
|
15859
|
+
diff_preview: z.string().max(1e4).optional()
|
|
15844
15860
|
}),
|
|
15845
15861
|
ci: z.object({
|
|
15846
15862
|
provider: z.string().max(40),
|
|
@@ -15856,7 +15872,8 @@ z.object({
|
|
|
15856
15872
|
ended_at: z.iso.datetime(),
|
|
15857
15873
|
exit_code: z.number().int(),
|
|
15858
15874
|
steps: z.array(Step).max(200),
|
|
15859
|
-
report: Report.optional()
|
|
15875
|
+
report: Report.optional(),
|
|
15876
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
15860
15877
|
});
|
|
15861
15878
|
const Policy = z.object({
|
|
15862
15879
|
version: z.number().int(),
|
|
@@ -16051,7 +16068,7 @@ const verifyEntitlementJwt = (jwt, options = {}) => {
|
|
|
16051
16068
|
const claims = parsed.data;
|
|
16052
16069
|
const expectedIssuer = process.env.RAIGAL_ISSUER?.trim() || "https://app.raigal.dev";
|
|
16053
16070
|
if (claims.iss !== expectedIssuer) throw new JwtVerificationError(`Untrusted issuer: ${claims.iss}`, "invalid_issuer");
|
|
16054
|
-
if (!isVersionAtLeast("1.0.
|
|
16071
|
+
if (!isVersionAtLeast("1.0.2", claims.min_cli_version)) throw new JwtVerificationError(`CLI version ${APP_VERSION} is below required minimum ${claims.min_cli_version}. Run "raigal update" or "npm install -g @methiu/raigal@latest".`, "cli_version_unsupported");
|
|
16055
16072
|
const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
16056
16073
|
const grace = options.allowGraceSeconds ?? 0;
|
|
16057
16074
|
if (now > claims.exp + grace) {
|
|
@@ -17916,6 +17933,17 @@ const detectRepoRef = (directory, ownerId) => {
|
|
|
17916
17933
|
};
|
|
17917
17934
|
};
|
|
17918
17935
|
//#endregion
|
|
17936
|
+
//#region src/output/rule-message.ts
|
|
17937
|
+
/**
|
|
17938
|
+
* Pure deterministic formatter for diagnostic messages.
|
|
17939
|
+
* Secret-class rules (or redactSource: true) unconditionally return FIXED_SECRET_DIAGNOSTIC_MESSAGE.
|
|
17940
|
+
* Non-secret rules return diagnostic.message (clamped to max 500 chars).
|
|
17941
|
+
*/
|
|
17942
|
+
const formatFindingMessage = (diagnostic) => {
|
|
17943
|
+
if (diagnostic.redactSource || isSecretClassRule(diagnostic.rule)) return FIXED_SECRET_DIAGNOSTIC_MESSAGE;
|
|
17944
|
+
return diagnostic.message.slice(0, 500);
|
|
17945
|
+
};
|
|
17946
|
+
//#endregion
|
|
17919
17947
|
//#region src/cloud/fingerprint.ts
|
|
17920
17948
|
/**
|
|
17921
17949
|
* Normalizes line text: trims leading/trailing whitespace and compresses
|
|
@@ -17955,7 +17983,8 @@ const toContractFinding = (diagnostic, rootDirectory, lineTextOverride) => {
|
|
|
17955
17983
|
severity,
|
|
17956
17984
|
path: relativePath,
|
|
17957
17985
|
line: Math.max(0, diagnostic.line),
|
|
17958
|
-
fingerprint
|
|
17986
|
+
fingerprint,
|
|
17987
|
+
message: formatFindingMessage(diagnostic)
|
|
17959
17988
|
};
|
|
17960
17989
|
};
|
|
17961
17990
|
//#endregion
|
|
@@ -19171,12 +19200,12 @@ const runScanBody = async (resolvedDir, config, options, projectInfo, scanScope,
|
|
|
19171
19200
|
scoreFileCount
|
|
19172
19201
|
});
|
|
19173
19202
|
if (options.sarif) {
|
|
19174
|
-
const { buildSarifLog } = await import("./sarif-
|
|
19203
|
+
const { buildSarifLog } = await import("./sarif-BHrT2Drf.js");
|
|
19175
19204
|
console.log(JSON.stringify(buildSarifLog(results), null, 2));
|
|
19176
19205
|
return completion;
|
|
19177
19206
|
}
|
|
19178
19207
|
if (options.json) {
|
|
19179
|
-
const { buildJsonOutput } = await import("./json-
|
|
19208
|
+
const { buildJsonOutput } = await import("./json-CjTR6e4V.js");
|
|
19180
19209
|
const jsonOut = buildJsonOutput(results, scoreResult, scoreFileCount, elapsedMs, scanCoverage);
|
|
19181
19210
|
console.log(JSON.stringify(jsonOut, null, 2));
|
|
19182
19211
|
return completion;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { n as withFindingAssessments, r as ENGINE_INFO, s as APP_VERSION, t as summarizeFindingAssessments } from "./cli.js";
|
|
3
3
|
//#region src/output/json.ts
|
|
4
4
|
const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs, coverage) => {
|
|
5
5
|
const allDiagnostics = results.flatMap((r) => r.diagnostics);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as APP_VERSION } from "./version-
|
|
1
|
+
import { t as APP_VERSION } from "./version-DW_ZBtce.js";
|
|
2
2
|
import { i as ENGINE_INFO, n as withFindingAssessments, t as summarizeFindingAssessments } from "./finding-assessment-M5fUTE-C.js";
|
|
3
3
|
//#region src/output/json.ts
|
|
4
4
|
const buildJsonOutput = (results, scoreResult, fileCount, elapsedMs, coverage) => {
|
package/dist/mcp.js
CHANGED
|
@@ -84,7 +84,7 @@ const getActiveToken = () => {
|
|
|
84
84
|
};
|
|
85
85
|
//#endregion
|
|
86
86
|
//#region src/version.ts
|
|
87
|
-
const APP_VERSION = "1.0.
|
|
87
|
+
const APP_VERSION = "1.0.2";
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/cloud/contract.ts
|
|
90
90
|
const Severity = z.enum(["error", "warning"]);
|
|
@@ -94,7 +94,8 @@ const Finding = z.object({
|
|
|
94
94
|
severity: Severity,
|
|
95
95
|
path: z.string().max(500),
|
|
96
96
|
line: z.number().int().nonnegative(),
|
|
97
|
-
fingerprint: z.string().length(32)
|
|
97
|
+
fingerprint: z.string().length(32),
|
|
98
|
+
message: z.string().max(500).optional()
|
|
98
99
|
});
|
|
99
100
|
const RepoRef = z.object({
|
|
100
101
|
provider: z.literal("github"),
|
|
@@ -109,12 +110,21 @@ const Step = z.object({
|
|
|
109
110
|
ms: z.number().int().nonnegative(),
|
|
110
111
|
counts: z.record(z.string(), z.number()).optional()
|
|
111
112
|
});
|
|
113
|
+
const AgentTelemetry = z.object({
|
|
114
|
+
provider: z.string().max(80),
|
|
115
|
+
before_score: z.number().min(0).max(100).nullable(),
|
|
116
|
+
after_score: z.number().min(0).max(100).nullable(),
|
|
117
|
+
pr_url: z.string().url().max(500).optional(),
|
|
118
|
+
patch_diff: z.string().max(2e4).optional(),
|
|
119
|
+
duration_ms: z.number().int().nonnegative().optional()
|
|
120
|
+
});
|
|
112
121
|
const Report = z.object({
|
|
113
122
|
score: z.number().min(0).max(100).nullable(),
|
|
114
123
|
scoreable: z.boolean(),
|
|
115
124
|
engine_scores: z.record(z.string(), z.number()).optional(),
|
|
116
125
|
files_scanned: z.number().int().nonnegative(),
|
|
117
|
-
findings: z.array(Finding).max(5e3)
|
|
126
|
+
findings: z.array(Finding).max(5e3),
|
|
127
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
118
128
|
});
|
|
119
129
|
z.object({
|
|
120
130
|
run_id: z.uuid(),
|
|
@@ -131,7 +141,13 @@ z.object({
|
|
|
131
141
|
branch: z.string().max(200).optional(),
|
|
132
142
|
head_sha: z.string().max(64).optional(),
|
|
133
143
|
base_ref: z.string().max(200).optional(),
|
|
134
|
-
pr_number: z.number().int().optional()
|
|
144
|
+
pr_number: z.number().int().optional(),
|
|
145
|
+
diff_summary: z.object({
|
|
146
|
+
files_changed: z.number().int().nonnegative(),
|
|
147
|
+
additions: z.number().int().nonnegative(),
|
|
148
|
+
deletions: z.number().int().nonnegative()
|
|
149
|
+
}).optional(),
|
|
150
|
+
diff_preview: z.string().max(1e4).optional()
|
|
135
151
|
}),
|
|
136
152
|
ci: z.object({
|
|
137
153
|
provider: z.string().max(40),
|
|
@@ -147,7 +163,8 @@ z.object({
|
|
|
147
163
|
ended_at: z.iso.datetime(),
|
|
148
164
|
exit_code: z.number().int(),
|
|
149
165
|
steps: z.array(Step).max(200),
|
|
150
|
-
report: Report.optional()
|
|
166
|
+
report: Report.optional(),
|
|
167
|
+
agent_telemetry: AgentTelemetry.optional()
|
|
151
168
|
});
|
|
152
169
|
z.object({
|
|
153
170
|
version: z.number().int(),
|
|
@@ -342,7 +359,7 @@ const verifyEntitlementJwt = (jwt, options = {}) => {
|
|
|
342
359
|
const claims = parsed.data;
|
|
343
360
|
const expectedIssuer = process.env.RAIGAL_ISSUER?.trim() || "https://app.raigal.dev";
|
|
344
361
|
if (claims.iss !== expectedIssuer) throw new JwtVerificationError(`Untrusted issuer: ${claims.iss}`, "invalid_issuer");
|
|
345
|
-
if (!isVersionAtLeast("1.0.
|
|
362
|
+
if (!isVersionAtLeast("1.0.2", claims.min_cli_version)) throw new JwtVerificationError(`CLI version ${APP_VERSION} is below required minimum ${claims.min_cli_version}. Run "raigal update" or "npm install -g @methiu/raigal@latest".`, "cli_version_unsupported");
|
|
346
363
|
const now = options.nowSeconds ?? Math.floor(Date.now() / 1e3);
|
|
347
364
|
const grace = options.allowGraceSeconds ?? 0;
|
|
348
365
|
if (now > claims.exp + grace) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as requestApi, c as log, i as detectRepoRef, o as getActiveToken } from "./cli.js";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
//#region src/commands/report-pr-closed.ts
|
|
5
|
+
const reportPrClosedCommand = async (options = {}) => {
|
|
6
|
+
try {
|
|
7
|
+
let prNumber = options.prNumber;
|
|
8
|
+
let merged = options.merged ?? false;
|
|
9
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
10
|
+
if (eventPath && fs.existsSync(eventPath)) try {
|
|
11
|
+
const eventData = JSON.parse(fs.readFileSync(eventPath, "utf-8"));
|
|
12
|
+
if (typeof eventData.pull_request?.number === "number") prNumber = eventData.pull_request.number;
|
|
13
|
+
else if (typeof eventData.number === "number") prNumber = eventData.number;
|
|
14
|
+
if (typeof eventData.pull_request?.merged === "boolean") merged = eventData.pull_request.merged;
|
|
15
|
+
} catch {}
|
|
16
|
+
if (!prNumber) {
|
|
17
|
+
log.info("No pull request number detected to report closed.");
|
|
18
|
+
return { exitCode: 0 };
|
|
19
|
+
}
|
|
20
|
+
const repo = detectRepoRef(process.cwd());
|
|
21
|
+
if (!repo) {
|
|
22
|
+
log.info("No repository detected.");
|
|
23
|
+
return { exitCode: 0 };
|
|
24
|
+
}
|
|
25
|
+
const token = getActiveToken()?.token;
|
|
26
|
+
await requestApi("/v1/pr-events", {
|
|
27
|
+
method: "POST",
|
|
28
|
+
token,
|
|
29
|
+
body: {
|
|
30
|
+
repo,
|
|
31
|
+
pr_number: prNumber,
|
|
32
|
+
event: "closed",
|
|
33
|
+
merged
|
|
34
|
+
},
|
|
35
|
+
timeoutMs: 3e3
|
|
36
|
+
});
|
|
37
|
+
log.info(`Reported PR #${prNumber} as ${merged ? "merged" : "closed"}.`);
|
|
38
|
+
return { exitCode: 0 };
|
|
39
|
+
} catch {
|
|
40
|
+
return { exitCode: 0 };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { reportPrClosedCommand };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { l as FIXED_SECRET_DIAGNOSTIC_MESSAGE, s as APP_VERSION, u as isSecretClassRule } from "./cli.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
//#region src/output/sarif.ts
|
|
5
5
|
const SARIF_VERSION = "2.1.0";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as APP_VERSION } from "./version-
|
|
1
|
+
import { t as APP_VERSION } from "./version-DW_ZBtce.js";
|
|
2
2
|
import { n as isSecretClassRule, t as FIXED_SECRET_DIAGNOSTIC_MESSAGE } from "./mask-secrets-BXn-ZSEh.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
//#region src/output/sarif.ts
|