infraweaver 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agents/opencode.d.ts +6 -0
- package/dist/agents/quotaTokens.d.ts +6 -0
- package/dist/cli.mjs +846 -412
- package/dist/index.js +806 -372
- package/dist/internal.js +4 -4
- package/dist/mcp/git.d.ts +6 -4
- package/dist/mcp/localContext.d.ts +7 -0
- package/dist/mcp/reviewCommentLimit.d.ts +55 -5
- package/dist/mcp/reviewMarkers.d.ts +5 -0
- package/dist/mcp/staleFix.d.ts +36 -1
- package/dist/mcp/terraform/awsPrices.d.ts +1 -1
- package/dist/mcp/terraform/azurePrices.d.ts +1 -1
- package/dist/mcp/terraform/concernResult.d.ts +9 -0
- package/dist/mcp/terraform/deltaSummary.d.ts +3 -0
- package/dist/mcp/terraform/hardcodedSecrets.d.ts +24 -10
- package/dist/mcp/terraform/refactorScope.d.ts +14 -2
- package/dist/mcp/terraform/ruleContext.d.ts +3 -0
- package/dist/mcp/terraform/scanSession.d.ts +2 -0
- package/dist/mcp/terraform/tree.d.ts +5 -0
- package/dist/mcp/terraform/types.d.ts +2 -1
- package/dist/mcp/terraform/verifySites.d.ts +56 -0
- package/dist/vendor/@infraweaver-io/models/tokenQuota.d.ts +7 -6
- package/package.json +2 -2
- package/src/agents/opencode.ts +8 -1
- package/src/agents/quotaTokens.ts +7 -1
- package/src/mcp/git.ts +64 -12
- package/src/mcp/localContext.ts +6 -1
- package/src/mcp/moduleExtraction.ts +5 -4
- package/src/mcp/review.ts +52 -3
- package/src/mcp/reviewCommentLimit.ts +169 -26
- package/src/mcp/reviewMarkers.ts +11 -0
- package/src/mcp/reviewProvenance.ts +1 -1
- package/src/mcp/staleFix.ts +73 -2
- package/src/mcp/terraform/awsPrices.ts +1 -1
- package/src/mcp/terraform/azurePrices.ts +23 -23
- package/src/mcp/terraform/concernResult.ts +18 -9
- package/src/mcp/terraform/deltaSummary.ts +4 -0
- package/src/mcp/terraform/hardcodedSecrets.ts +148 -27
- package/src/mcp/terraform/nativeRuleScanners.ts +2 -1
- package/src/mcp/terraform/nativeScan.ts +4 -0
- package/src/mcp/terraform/refactor/equivalence.ts +42 -9
- package/src/mcp/terraform/refactorScope.ts +90 -21
- package/src/mcp/terraform/ruleContext.ts +4 -0
- package/src/mcp/terraform/scanDelta.ts +67 -26
- package/src/mcp/terraform/scanSession.ts +6 -0
- package/src/mcp/terraform/tools/detectPlanDrift.ts +2 -0
- package/src/mcp/terraform/tools/ingestExternalFindings.ts +2 -0
- package/src/mcp/terraform/tools/normalizationCandidates.ts +5 -5
- package/src/mcp/terraform/tools/readFindings.ts +2 -0
- package/src/mcp/terraform/tools/scan.ts +3 -0
- package/src/mcp/terraform/tools/verifyRemediation.ts +23 -1
- package/src/mcp/terraform/tree.ts +8 -0
- package/src/mcp/terraform/types.ts +2 -1
- package/src/mcp/terraform/verifySites.ts +124 -0
- package/src/modes/refactor.ts +1 -1
- package/src/modes/remediate-and-refactor.ts +1 -1
- package/src/modes/remediate.ts +1 -1
- package/src/phases/runAgentWithWatchdogs.ts +3 -2
package/dist/index.js
CHANGED
|
@@ -84161,14 +84161,14 @@ var require_turndown_cjs = __commonJS({
|
|
|
84161
84161
|
} else if (node3.nodeType === 1) {
|
|
84162
84162
|
replacement = replacementForNode.call(self2, node3);
|
|
84163
84163
|
}
|
|
84164
|
-
return
|
|
84164
|
+
return join75(output2, replacement);
|
|
84165
84165
|
}, "");
|
|
84166
84166
|
}
|
|
84167
84167
|
function postProcess(output2) {
|
|
84168
84168
|
var self2 = this;
|
|
84169
84169
|
this.rules.forEach(function(rule) {
|
|
84170
84170
|
if (typeof rule.append === "function") {
|
|
84171
|
-
output2 =
|
|
84171
|
+
output2 = join75(output2, rule.append(self2.options));
|
|
84172
84172
|
}
|
|
84173
84173
|
});
|
|
84174
84174
|
return output2.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
|
|
@@ -84180,7 +84180,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
84180
84180
|
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
|
84181
84181
|
return whitespace.leading + rule.replacement(content, node3, this.options) + whitespace.trailing;
|
|
84182
84182
|
}
|
|
84183
|
-
function
|
|
84183
|
+
function join75(output2, replacement) {
|
|
84184
84184
|
var s1 = trimTrailingNewlines(output2);
|
|
84185
84185
|
var s2 = trimLeadingNewlines(replacement);
|
|
84186
84186
|
var nls = Math.max(output2.length - s1.length, replacement.length - s2.length);
|
|
@@ -97300,7 +97300,7 @@ var require_polyfill = __commonJS({
|
|
|
97300
97300
|
var {
|
|
97301
97301
|
dirname: dirname15,
|
|
97302
97302
|
isAbsolute: isAbsolute7,
|
|
97303
|
-
join:
|
|
97303
|
+
join: join75,
|
|
97304
97304
|
parse: parse8,
|
|
97305
97305
|
resolve: resolve11,
|
|
97306
97306
|
sep: sep11,
|
|
@@ -97557,8 +97557,8 @@ var require_polyfill = __commonJS({
|
|
|
97557
97557
|
const dir = await readdir2(src);
|
|
97558
97558
|
for (let i = 0; i < dir.length; i++) {
|
|
97559
97559
|
const item = dir[i];
|
|
97560
|
-
const srcItem =
|
|
97561
|
-
const destItem =
|
|
97560
|
+
const srcItem = join75(src, item);
|
|
97561
|
+
const destItem = join75(dest, item);
|
|
97562
97562
|
const { destStat } = await checkPaths2(srcItem, destItem, opts);
|
|
97563
97563
|
await startCopy(destStat, srcItem, destItem, opts);
|
|
97564
97564
|
}
|
|
@@ -97631,7 +97631,7 @@ var require_cp = __commonJS({
|
|
|
97631
97631
|
// node_modules/.pnpm/@npmcli+fs@6.0.0/node_modules/@npmcli/fs/lib/with-temp-dir.js
|
|
97632
97632
|
var require_with_temp_dir = __commonJS({
|
|
97633
97633
|
"node_modules/.pnpm/@npmcli+fs@6.0.0/node_modules/@npmcli/fs/lib/with-temp-dir.js"(exports2, module) {
|
|
97634
|
-
var { join:
|
|
97634
|
+
var { join: join75, sep: sep11 } = __require("path");
|
|
97635
97635
|
var getOptions2 = require_get_options();
|
|
97636
97636
|
var { mkdir: mkdir5, mkdtemp, rm: rm2 } = __require("fs/promises");
|
|
97637
97637
|
var withTempDir = async (root, fn2, opts) => {
|
|
@@ -97639,7 +97639,7 @@ var require_with_temp_dir = __commonJS({
|
|
|
97639
97639
|
copy: ["tmpPrefix"]
|
|
97640
97640
|
});
|
|
97641
97641
|
await mkdir5(root, { recursive: true });
|
|
97642
|
-
const target = await mkdtemp(
|
|
97642
|
+
const target = await mkdtemp(join75(`${root}${sep11}`, options.tmpPrefix || ""));
|
|
97643
97643
|
let err;
|
|
97644
97644
|
let result;
|
|
97645
97645
|
try {
|
|
@@ -97664,13 +97664,13 @@ var require_with_temp_dir = __commonJS({
|
|
|
97664
97664
|
var require_readdir_scoped = __commonJS({
|
|
97665
97665
|
"node_modules/.pnpm/@npmcli+fs@6.0.0/node_modules/@npmcli/fs/lib/readdir-scoped.js"(exports2, module) {
|
|
97666
97666
|
var { readdir: readdir2 } = __require("fs/promises");
|
|
97667
|
-
var { join:
|
|
97667
|
+
var { join: join75 } = __require("path");
|
|
97668
97668
|
var readdirScoped = async (dir) => {
|
|
97669
97669
|
const results = [];
|
|
97670
97670
|
for (const item of await readdir2(dir)) {
|
|
97671
97671
|
if (item.startsWith("@")) {
|
|
97672
|
-
for (const scopedItem of await readdir2(
|
|
97673
|
-
results.push(
|
|
97672
|
+
for (const scopedItem of await readdir2(join75(dir, item))) {
|
|
97673
|
+
results.push(join75(item, scopedItem));
|
|
97674
97674
|
}
|
|
97675
97675
|
} else {
|
|
97676
97676
|
results.push(item);
|
|
@@ -97685,7 +97685,7 @@ var require_readdir_scoped = __commonJS({
|
|
|
97685
97685
|
// node_modules/.pnpm/@npmcli+fs@6.0.0/node_modules/@npmcli/fs/lib/move-file.js
|
|
97686
97686
|
var require_move_file = __commonJS({
|
|
97687
97687
|
"node_modules/.pnpm/@npmcli+fs@6.0.0/node_modules/@npmcli/fs/lib/move-file.js"(exports2, module) {
|
|
97688
|
-
var { dirname: dirname15, join:
|
|
97688
|
+
var { dirname: dirname15, join: join75, resolve: resolve11, relative: relative8, isAbsolute: isAbsolute7 } = __require("path");
|
|
97689
97689
|
var fs12 = __require("fs/promises");
|
|
97690
97690
|
var pathExists2 = async (path15) => {
|
|
97691
97691
|
try {
|
|
@@ -97715,7 +97715,7 @@ var require_move_file = __commonJS({
|
|
|
97715
97715
|
if (sourceStat.isDirectory()) {
|
|
97716
97716
|
const files = await fs12.readdir(source);
|
|
97717
97717
|
await Promise.all(files.map(
|
|
97718
|
-
(file2) => moveFile(
|
|
97718
|
+
(file2) => moveFile(join75(source, file2), join75(destination, file2), options, false, symlinks)
|
|
97719
97719
|
));
|
|
97720
97720
|
} else if (sourceStat.isSymbolicLink()) {
|
|
97721
97721
|
symlinks.push({ source, destination });
|
|
@@ -107552,23 +107552,23 @@ var require_helpers = __commonJS({
|
|
|
107552
107552
|
"node_modules/.pnpm/ip-address@10.7.3/node_modules/ip-address/dist/v6/helpers.js"(exports2) {
|
|
107553
107553
|
"use strict";
|
|
107554
107554
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
107555
|
-
exports2.escapeHtml =
|
|
107555
|
+
exports2.escapeHtml = escapeHtml2;
|
|
107556
107556
|
exports2.spanAllZeroes = spanAllZeroes;
|
|
107557
107557
|
exports2.spanAll = spanAll;
|
|
107558
107558
|
exports2.spanLeadingZeroes = spanLeadingZeroes;
|
|
107559
107559
|
exports2.simpleGroup = simpleGroup;
|
|
107560
|
-
function
|
|
107560
|
+
function escapeHtml2(s) {
|
|
107561
107561
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
107562
107562
|
}
|
|
107563
107563
|
function spanAllZeroes(s) {
|
|
107564
|
-
return
|
|
107564
|
+
return escapeHtml2(s).replace(/(0+)/g, '<span class="zero">$1</span>');
|
|
107565
107565
|
}
|
|
107566
107566
|
function spanAll(s, offset = 0) {
|
|
107567
107567
|
const letters = s.split("");
|
|
107568
|
-
return letters.map((n, i) => `<span class="digit value-${
|
|
107568
|
+
return letters.map((n, i) => `<span class="digit value-${escapeHtml2(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`).join("");
|
|
107569
107569
|
}
|
|
107570
107570
|
function spanLeadingZeroesSimple(group2) {
|
|
107571
|
-
return
|
|
107571
|
+
return escapeHtml2(group2).replace(/^(0+)/, '<span class="zero">$1</span>');
|
|
107572
107572
|
}
|
|
107573
107573
|
function spanLeadingZeroes(address) {
|
|
107574
107574
|
const groups2 = address.split(":");
|
|
@@ -160384,7 +160384,7 @@ var init_cacheTwirpClient = __esm({
|
|
|
160384
160384
|
});
|
|
160385
160385
|
|
|
160386
160386
|
// node_modules/.pnpm/@actions+cache@6.3.0_supports-color@7.2.0/node_modules/@actions/cache/lib/internal/tar.js
|
|
160387
|
-
import { existsSync as
|
|
160387
|
+
import { existsSync as existsSync16, writeFileSync as writeFileSync21 } from "fs";
|
|
160388
160388
|
import * as path13 from "path";
|
|
160389
160389
|
function getTarPath() {
|
|
160390
160390
|
return __awaiter18(this, void 0, void 0, function* () {
|
|
@@ -160394,7 +160394,7 @@ function getTarPath() {
|
|
|
160394
160394
|
const systemTar = SystemTarPathOnWindows;
|
|
160395
160395
|
if (gnuTar) {
|
|
160396
160396
|
return { path: gnuTar, type: ArchiveToolType.GNU };
|
|
160397
|
-
} else if (
|
|
160397
|
+
} else if (existsSync16(systemTar)) {
|
|
160398
160398
|
return { path: systemTar, type: ArchiveToolType.BSD };
|
|
160399
160399
|
}
|
|
160400
160400
|
break;
|
|
@@ -250325,7 +250325,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
250325
250325
|
}
|
|
250326
250326
|
};
|
|
250327
250327
|
|
|
250328
|
-
// node_modules/.pnpm/@infraweaver-io+models@0.1.
|
|
250328
|
+
// node_modules/.pnpm/@infraweaver-io+models@0.1.7/node_modules/@infraweaver-io/models/dist/catalog.js
|
|
250329
250329
|
function provider(config3) {
|
|
250330
250330
|
return config3;
|
|
250331
250331
|
}
|
|
@@ -258848,7 +258848,7 @@ function isGeminiRouted(ctx) {
|
|
|
258848
258848
|
init_core3();
|
|
258849
258849
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
258850
258850
|
|
|
258851
|
-
// node_modules/.pnpm/@infraweaver-io+models@0.1.
|
|
258851
|
+
// node_modules/.pnpm/@infraweaver-io+models@0.1.7/node_modules/@infraweaver-io/models/dist/usage.js
|
|
258852
258852
|
function formatCostUsd(costUsd) {
|
|
258853
258853
|
return costUsd.toFixed(4);
|
|
258854
258854
|
}
|
|
@@ -259203,7 +259203,7 @@ import { randomBytes as randomBytes2 } from "node:crypto";
|
|
|
259203
259203
|
// package.json
|
|
259204
259204
|
var package_default = {
|
|
259205
259205
|
name: "infraweaver",
|
|
259206
|
-
version: "0.3.
|
|
259206
|
+
version: "0.3.13",
|
|
259207
259207
|
description: "GitHub Action that remediates Terraform to best practices and opens one scoped pull request per concern.",
|
|
259208
259208
|
keywords: [
|
|
259209
259209
|
"ai-coding-agent",
|
|
@@ -259306,7 +259306,7 @@ var package_default = {
|
|
|
259306
259306
|
"@infraweaver-io/ci": "^0.1.8",
|
|
259307
259307
|
"@infraweaver-io/core": "^0.1.5",
|
|
259308
259308
|
"@infraweaver-io/crosswalk": "^1.2.0",
|
|
259309
|
-
"@infraweaver-io/models": "^0.1.
|
|
259309
|
+
"@infraweaver-io/models": "^0.1.7",
|
|
259310
259310
|
"@infraweaver-io/policy-spec": "^1.2.0",
|
|
259311
259311
|
"@infraweaver-io/report-contract": "^0.1.5",
|
|
259312
259312
|
"@infraweaver-io/sandbox": "^0.1.8",
|
|
@@ -266110,7 +266110,18 @@ var SECRET_WORDS = /* @__PURE__ */ new Set([
|
|
|
266110
266110
|
"credential",
|
|
266111
266111
|
"credentials"
|
|
266112
266112
|
]);
|
|
266113
|
-
var SECRET_KEY_PREFIXES = /* @__PURE__ */ new Set([
|
|
266113
|
+
var SECRET_KEY_PREFIXES = /* @__PURE__ */ new Set([
|
|
266114
|
+
"api",
|
|
266115
|
+
"secret",
|
|
266116
|
+
"private",
|
|
266117
|
+
"signing",
|
|
266118
|
+
"access",
|
|
266119
|
+
"account",
|
|
266120
|
+
"client",
|
|
266121
|
+
"shared",
|
|
266122
|
+
"preshared",
|
|
266123
|
+
"master"
|
|
266124
|
+
]);
|
|
266114
266125
|
var NOT_SECRET_TOKENS = /* @__PURE__ */ new Set(["creation", "idempotency", "client", "request", "continuation"]);
|
|
266115
266126
|
function words(name) {
|
|
266116
266127
|
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[_-]+/).filter(Boolean);
|
|
@@ -266122,24 +266133,70 @@ function isSecretName(name) {
|
|
|
266122
266133
|
if (last === void 0) return false;
|
|
266123
266134
|
if (last === "key") return prev !== void 0 && SECRET_KEY_PREFIXES.has(prev);
|
|
266124
266135
|
if (last === "token" && prev !== void 0 && NOT_SECRET_TOKENS.has(prev)) return false;
|
|
266136
|
+
if (last === "string") return prev === "connection";
|
|
266137
|
+
if (last === "secret" && w.length === 1) return false;
|
|
266125
266138
|
return SECRET_WORDS.has(last);
|
|
266126
266139
|
}
|
|
266127
266140
|
function isPlaceholder(inner) {
|
|
266128
|
-
return inner.trim() === "" || /^[*xX.]+$/.test(inner) || /^<[^>]*>$/.test(inner) || //
|
|
266129
|
-
|
|
266141
|
+
return inner.trim() === "" || /^[*xX.]+$/.test(inner) || /^<[^>]*>$/.test(inner) || /^(?:true|false|null)$/.test(inner) || /^-?\d+(?:\.\d+)?$/.test(inner) || // a template directive is computed, like an interpolation: `"%{ if … }…%{ endif }"`
|
|
266142
|
+
inner.includes("%{") || // the dummy credentials offline plans and LocalStack are given (`secret_key = "test"`,
|
|
266143
|
+
// `"example-secret"`) — but only when that is the whole value: a lowercase tail at
|
|
266144
|
+
// most, so `"Test-Pr0dDbPassw0rd!"` is a password that happens to start with a word
|
|
266145
|
+
isDummy(inner) || // a token's lifetime unit: `token_validity_units { access_token = "hours" }`
|
|
266130
266146
|
/^(?:seconds|minutes|hours|days)$/.test(inner);
|
|
266131
266147
|
}
|
|
266132
|
-
|
|
266148
|
+
function isDummy(inner) {
|
|
266149
|
+
const m = /^(?:test|mock|fake|dummy|fixture|example|placeholder|sample)([_-].*)?$/i.exec(inner);
|
|
266150
|
+
return m !== null && (m[1] === void 0 || /^[_-][a-z0-9_-]*$/.test(m[1]));
|
|
266151
|
+
}
|
|
266152
|
+
function isSecretReference(inner) {
|
|
266153
|
+
return inner.startsWith("arn:") || /^projects\/[^/]+\/secrets\//.test(inner) || /^https:\/\/[\w-]+\.vault\.azure\.net\/secrets\//i.test(inner) || /^\/[\w./-]+$/.test(inner);
|
|
266154
|
+
}
|
|
266155
|
+
var HEADER = /^(resource|data|provider|module|locals|variable|output|terraform)\b([^{]*)\{(.*)$/;
|
|
266133
266156
|
var ASSIGNMENT = /^\s*(?:"([A-Za-z_][\w-]*)"|([A-Za-z_][\w-]*))\s*=(?!=)\s*(.*)$/;
|
|
266134
266157
|
var HEREDOC = /<<-?([A-Za-z_]\w*)\s*$/;
|
|
266135
266158
|
var INLINE_PAIR = /(?:"([A-Za-z_][\w-]*)"|\b([A-Za-z_][\w-]*))\s*=(?!=)\s*("(?:[^"\\]|\\.)*")/g;
|
|
266136
|
-
function literalValue(raw2) {
|
|
266159
|
+
function literalValue(name, raw2) {
|
|
266137
266160
|
const value2 = stripTrailingComment(raw2).replace(/,$/, "").trim();
|
|
266138
|
-
|
|
266161
|
+
if (!isStringLiteral(value2)) return false;
|
|
266162
|
+
const inner = value2.slice(1, -1);
|
|
266163
|
+
if (isPlaceholder(inner) || isSecretReference(inner)) return false;
|
|
266164
|
+
return !(words(name).at(-1) === "auth" && /^[A-Z]+(?:_[A-Z]+)*$/.test(inner));
|
|
266165
|
+
}
|
|
266166
|
+
function variableName(holder) {
|
|
266167
|
+
return /^variable\s+"?([\w-]+)"?/.exec(holder)?.[1] ?? "";
|
|
266168
|
+
}
|
|
266169
|
+
function opensBlockComment(line) {
|
|
266170
|
+
for (let i = 0; i < line.length; i++) {
|
|
266171
|
+
const span = skipNonCode(line, i);
|
|
266172
|
+
if (!span) continue;
|
|
266173
|
+
if (line.startsWith("/*", i) && !line.includes("*/", i + 2)) return true;
|
|
266174
|
+
i = span.end;
|
|
266175
|
+
}
|
|
266176
|
+
return false;
|
|
266177
|
+
}
|
|
266178
|
+
function closesOnLine(rest) {
|
|
266179
|
+
let depth = 1;
|
|
266180
|
+
for (let i = 0; i < rest.length; i++) {
|
|
266181
|
+
const span = skipNonCode(rest, i);
|
|
266182
|
+
if (span) {
|
|
266183
|
+
i = span.end;
|
|
266184
|
+
continue;
|
|
266185
|
+
}
|
|
266186
|
+
if (rest[i] === "{") depth++;
|
|
266187
|
+
else if (rest[i] === "}" && --depth === 0) return true;
|
|
266188
|
+
}
|
|
266189
|
+
return false;
|
|
266139
266190
|
}
|
|
266140
266191
|
function findHardcodedSecrets(hcl2) {
|
|
266192
|
+
return findInLines(hcl2, null);
|
|
266193
|
+
}
|
|
266194
|
+
function findTfvarsSecrets(hcl2, path15) {
|
|
266195
|
+
return findInLines(hcl2, `tfvars input ${path15}`);
|
|
266196
|
+
}
|
|
266197
|
+
function findInLines(hcl2, fileHolder) {
|
|
266141
266198
|
const out = [];
|
|
266142
|
-
let holder =
|
|
266199
|
+
let holder = fileHolder;
|
|
266143
266200
|
let heredoc = null;
|
|
266144
266201
|
let inComment = false;
|
|
266145
266202
|
const lines = hcl2.split("\n");
|
|
@@ -266159,12 +266216,28 @@ function findHardcodedSecrets(hcl2) {
|
|
|
266159
266216
|
continue;
|
|
266160
266217
|
}
|
|
266161
266218
|
if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
|
|
266162
|
-
|
|
266219
|
+
if (opensBlockComment(line)) inComment = true;
|
|
266220
|
+
const header = fileHolder === null ? HEADER.exec(line) : null;
|
|
266163
266221
|
if (header) {
|
|
266164
266222
|
holder = `${header[1]}${header[2].trimEnd() ? ` ${header[2].trim()}` : ""}`;
|
|
266223
|
+
const rest = header[3];
|
|
266224
|
+
const opens2 = HEREDOC.exec(rest);
|
|
266225
|
+
if (opens2) heredoc = opens2[1];
|
|
266226
|
+
if (!holder.startsWith("output ") && !holder.startsWith("terraform")) {
|
|
266227
|
+
for (const pair of rest.matchAll(INLINE_PAIR)) {
|
|
266228
|
+
const key = pair[1] ?? pair[2];
|
|
266229
|
+
const isVariable = holder.startsWith("variable ");
|
|
266230
|
+
if (isVariable && key !== "default") continue;
|
|
266231
|
+
const name2 = isVariable ? variableName(holder) : key;
|
|
266232
|
+
if (isSecretName(name2) && literalValue(name2, pair[3])) {
|
|
266233
|
+
out.push({ name: name2, holder, line: i + 1 });
|
|
266234
|
+
}
|
|
266235
|
+
}
|
|
266236
|
+
}
|
|
266237
|
+
if (closesOnLine(rest)) holder = null;
|
|
266165
266238
|
continue;
|
|
266166
266239
|
}
|
|
266167
|
-
if (line.startsWith("}")) {
|
|
266240
|
+
if (fileHolder === null && line.startsWith("}")) {
|
|
266168
266241
|
holder = null;
|
|
266169
266242
|
continue;
|
|
266170
266243
|
}
|
|
@@ -266176,30 +266249,34 @@ function findHardcodedSecrets(hcl2) {
|
|
|
266176
266249
|
const name = m[1] ?? m[2];
|
|
266177
266250
|
const value2 = m[3];
|
|
266178
266251
|
if (holder.startsWith("variable ")) {
|
|
266179
|
-
const variable =
|
|
266180
|
-
if (name === "default" && isSecretName(variable) && literalValue(value2)) {
|
|
266252
|
+
const variable = variableName(holder);
|
|
266253
|
+
if (name === "default" && isSecretName(variable) && literalValue(variable, value2)) {
|
|
266181
266254
|
out.push({ name: variable, holder, line: i + 1 });
|
|
266182
266255
|
}
|
|
266183
266256
|
continue;
|
|
266184
266257
|
}
|
|
266185
266258
|
if (holder.startsWith("output ") || holder.startsWith("terraform")) continue;
|
|
266186
|
-
if (isSecretName(name) && literalValue(value2)) {
|
|
266259
|
+
if (isSecretName(name) && literalValue(name, value2)) {
|
|
266187
266260
|
out.push({ name, holder, line: i + 1 });
|
|
266188
266261
|
continue;
|
|
266189
266262
|
}
|
|
266190
266263
|
for (const pair of value2.matchAll(INLINE_PAIR)) {
|
|
266191
266264
|
const key = pair[1] ?? pair[2];
|
|
266192
|
-
if (isSecretName(key) && literalValue(pair[3])) {
|
|
266265
|
+
if (isSecretName(key) && literalValue(key, pair[3])) {
|
|
266193
266266
|
out.push({ name: key, holder, line: i + 1 });
|
|
266194
266267
|
}
|
|
266195
266268
|
}
|
|
266196
266269
|
}
|
|
266197
266270
|
return out;
|
|
266198
266271
|
}
|
|
266199
|
-
function scanHardcodedSecrets(files) {
|
|
266272
|
+
function scanHardcodedSecrets(files, tfvarsFiles = []) {
|
|
266200
266273
|
const concerns = [];
|
|
266201
|
-
|
|
266202
|
-
|
|
266274
|
+
const hits = [
|
|
266275
|
+
...files.map((f) => ({ path: f.path, found: findHardcodedSecrets(f.hcl) })),
|
|
266276
|
+
...tfvarsFiles.map((f) => ({ path: f.path, found: findTfvarsSecrets(f.hcl, f.path) }))
|
|
266277
|
+
];
|
|
266278
|
+
for (const { path: path15, found } of hits) {
|
|
266279
|
+
for (const hit of found) {
|
|
266203
266280
|
concerns.push(
|
|
266204
266281
|
buildConcern({
|
|
266205
266282
|
source: NATIVE_SOURCE,
|
|
@@ -268202,7 +268279,8 @@ var NATIVE_RULE_SCANNERS = [
|
|
|
268202
268279
|
name: "hardcoded-secrets",
|
|
268203
268280
|
rules: [HARDCODED_SECRET_ARGUMENT],
|
|
268204
268281
|
// Per file: the argument's name and its literal are both on the line itself.
|
|
268205
|
-
|
|
268282
|
+
// The only rule that reads `.tfvars`: an input file holds values, not config.
|
|
268283
|
+
scan: (ctx) => ({ concerns: scanHardcodedSecrets(ctx.files, ctx.tfvarsFiles) })
|
|
268206
268284
|
},
|
|
268207
268285
|
{
|
|
268208
268286
|
name: "write-only",
|
|
@@ -268287,6 +268365,7 @@ function createRuleContext(input2) {
|
|
|
268287
268365
|
cwd: input2.cwd,
|
|
268288
268366
|
files: input2.files,
|
|
268289
268367
|
tofuFiles: input2.tofuFiles ?? [],
|
|
268368
|
+
tfvarsFiles: input2.tfvarsFiles ?? [],
|
|
268290
268369
|
truncated: input2.truncated ?? null,
|
|
268291
268370
|
repeatedLiteralThreshold: input2.repeatedLiteralThreshold
|
|
268292
268371
|
};
|
|
@@ -268338,6 +268417,9 @@ function readTfTree(cwd, limits) {
|
|
|
268338
268417
|
function readTofuTree(cwd, limits) {
|
|
268339
268418
|
return readTree(cwd, ".tofu", limits);
|
|
268340
268419
|
}
|
|
268420
|
+
function readTfvarsTree(cwd, limits) {
|
|
268421
|
+
return readTree(cwd, ".tfvars", limits);
|
|
268422
|
+
}
|
|
268341
268423
|
var OVERSIZE_NAMED = 5;
|
|
268342
268424
|
function describeOversize(paths) {
|
|
268343
268425
|
const named = paths.slice(0, OVERSIZE_NAMED).join(", ");
|
|
@@ -268366,6 +268448,9 @@ function scanNative(cwd, opts = {}) {
|
|
|
268366
268448
|
// walk over a suffix most repos do not use at all, and threading it through
|
|
268367
268449
|
// the context keeps the scanners uniform.
|
|
268368
268450
|
tofuFiles: readTofuTree(cwd).files,
|
|
268451
|
+
// likewise only for the hardcoded-secret rule: a value kept out of the `.tf`
|
|
268452
|
+
// source is most often committed here instead
|
|
268453
|
+
tfvarsFiles: readTfvarsTree(cwd).files,
|
|
268369
268454
|
truncated: tree.truncated,
|
|
268370
268455
|
repeatedLiteralThreshold: opts.repeatedLiteralThreshold ?? DEFAULT_REPEAT_THRESHOLD
|
|
268371
268456
|
});
|
|
@@ -272923,9 +273008,9 @@ function TerraformChangeSummaryTool(ctx) {
|
|
|
272923
273008
|
}
|
|
272924
273009
|
|
|
272925
273010
|
// src/mcp/checkout.ts
|
|
272926
|
-
import { createHash as
|
|
273011
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
272927
273012
|
import { statSync as statSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
272928
|
-
import { join as
|
|
273013
|
+
import { join as join36 } from "node:path";
|
|
272929
273014
|
|
|
272930
273015
|
// node_modules/.pnpm/@infraweaver-io+ci@0.1.8/node_modules/@infraweaver-io/ci/dist/diffCoverage.js
|
|
272931
273016
|
import { isAbsolute as isAbsolute3, normalize as normalize3, resolve as resolve5 } from "node:path";
|
|
@@ -273331,6 +273416,9 @@ import { spawnSync as spawnSync5 } from "node:child_process";
|
|
|
273331
273416
|
import { readFileSync as readFileSync12, rmSync as rmSync2 } from "node:fs";
|
|
273332
273417
|
import { join as join22 } from "node:path";
|
|
273333
273418
|
|
|
273419
|
+
// src/mcp/staleFix.ts
|
|
273420
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
273421
|
+
|
|
273334
273422
|
// node_modules/.pnpm/@infraweaver-io+ci@0.1.8/node_modules/@infraweaver-io/ci/dist/progressComment.js
|
|
273335
273423
|
function parseProgressComment(raw2) {
|
|
273336
273424
|
if (!raw2?.id)
|
|
@@ -274283,7 +274371,31 @@ function groupIdFromBranch(branch) {
|
|
|
274283
274371
|
}
|
|
274284
274372
|
function remediationBranchSuffix(base, defaultBranch) {
|
|
274285
274373
|
if (!base || !defaultBranch || base === defaultBranch) return "";
|
|
274286
|
-
|
|
274374
|
+
const slug2 = base.replace(/[^A-Za-z0-9._-]+/g, "-");
|
|
274375
|
+
if (slug2 === base) return `--${slug2}`;
|
|
274376
|
+
return `--${slug2}-${createHash6("sha1").update(base).digest("hex").slice(0, 8)}`;
|
|
274377
|
+
}
|
|
274378
|
+
function remediationBranchFor(id, base, defaultBranch, open3) {
|
|
274379
|
+
const computed = `remediate/${id}${remediationBranchSuffix(base, defaultBranch)}`;
|
|
274380
|
+
const heads = (open3 ?? []).filter((pr) => pr.base === base && groupIdFromBranch(pr.head) === id).map((pr) => pr.head).filter((head) => !(open3 ?? []).some((pr) => pr.head === head && pr.base !== base));
|
|
274381
|
+
return heads.includes(computed) ? computed : heads[0] ?? computed;
|
|
274382
|
+
}
|
|
274383
|
+
async function listOpenRemediationPrs(ctx) {
|
|
274384
|
+
const { octokit, repo } = ctx;
|
|
274385
|
+
if (ctx.toolState?.selectedMode !== "Remediate") return [];
|
|
274386
|
+
if (!octokit || !repo?.owner || !repo.name) return [];
|
|
274387
|
+
try {
|
|
274388
|
+
const open3 = await octokit.paginate(octokit.rest.pulls.list, {
|
|
274389
|
+
owner: repo.owner,
|
|
274390
|
+
repo: repo.name,
|
|
274391
|
+
state: "open",
|
|
274392
|
+
per_page: 100
|
|
274393
|
+
});
|
|
274394
|
+
return open3.filter((pr) => pr.head.repo?.id === pr.base.repo.id && groupIdFromBranch(pr.head.ref)).map((pr) => ({ head: pr.head.ref, base: pr.base.ref }));
|
|
274395
|
+
} catch (e) {
|
|
274396
|
+
log2.warning(`\xBB could not list open remediation PRs: ${errorMessage(e)}`);
|
|
274397
|
+
return [];
|
|
274398
|
+
}
|
|
274287
274399
|
}
|
|
274288
274400
|
function matchesBotIdentity(identity) {
|
|
274289
274401
|
const normalized = identity.replace(/\[bot\]$/i, "").toLowerCase();
|
|
@@ -274539,13 +274651,13 @@ function ClosePullRequestTool(ctx) {
|
|
|
274539
274651
|
}
|
|
274540
274652
|
|
|
274541
274653
|
// src/mcp/terraform/emittedArtefacts.ts
|
|
274542
|
-
import { createHash as
|
|
274654
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
274543
274655
|
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
274544
274656
|
import { resolve as resolve6 } from "node:path";
|
|
274545
274657
|
var ARTEFACT_DIR = "compliance/";
|
|
274546
274658
|
function gitBlobId(bytes) {
|
|
274547
274659
|
const content = Buffer.from(bytes, "utf8");
|
|
274548
|
-
return
|
|
274660
|
+
return createHash7("sha1").update(`blob ${content.length}\0`).update(content).digest("hex");
|
|
274549
274661
|
}
|
|
274550
274662
|
function writeEmittedArtefact(toolState, path15, bytes) {
|
|
274551
274663
|
writeFileSync4(path15, bytes);
|
|
@@ -274895,7 +275007,7 @@ function parseResourcesWithArgs(hcl2) {
|
|
|
274895
275007
|
}
|
|
274896
275008
|
|
|
274897
275009
|
// src/mcp/terraform/refactor/workspace.ts
|
|
274898
|
-
import { createHash as
|
|
275010
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
274899
275011
|
import { readdirSync as readdirSync4, readFileSync as readFileSync11 } from "node:fs";
|
|
274900
275012
|
import { join as join21, posix as posix6 } from "node:path";
|
|
274901
275013
|
function readTreeAtRef(cwd, ref) {
|
|
@@ -274925,7 +275037,7 @@ function readWorkingTree(cwd) {
|
|
|
274925
275037
|
return files;
|
|
274926
275038
|
}
|
|
274927
275039
|
function workingTreeFingerprint(files) {
|
|
274928
|
-
const h =
|
|
275040
|
+
const h = createHash8("sha256");
|
|
274929
275041
|
for (const f of [...files].sort((a, b) => a.path.localeCompare(b.path, "en"))) {
|
|
274930
275042
|
h.update(f.path);
|
|
274931
275043
|
h.update("\0");
|
|
@@ -276636,7 +276748,7 @@ This mode standardises STRUCTURE while preserving BEHAVIOUR \u2014 the equivalen
|
|
|
276636
276748
|
- \`${t("terraform_normalization_candidates")}\` \u2192 in-place idiomatic cleanups that change SYNTAX, not behaviour (redundant whole-string \`"\${expr}"\` interpolation; legacy HCL0.11 map-argument block syntax like \`vars {\` on a \`template_file\`). These relocate NOTHING \u2014 zero \`moved {}\` blocks \u2014 and are proven by the same equivalence check.
|
|
276637
276749
|
- \`${t("terraform_consolidation_candidates")}\` \u2192 the SAME resource shape declared in several root directories (\`env/dev\` + \`env/staging\` + \`env/prod\`), with the single parameterised module they could all call already derived: which attributes are identical (module content) and which differ (per-environment inputs). A member root of a group will ALSO show up as a zero-candidate cluster in \`${t("module_extraction_candidates")}\` \u2014 prefer the consolidation, which does that work once for every environment instead of once per environment. Its \`near_groups\` are the opposite case: roots recognisably the same stack that DIFFER (one carries a resource the other does not), where folding them together is a design decision this mode has no basis for. Do NOT extract a near-group root's shared resources into a module on its own either \u2014 a module one twin calls and the other does not widens exactly the drift the near-group reports. Leave those roots alone and name the near-group and its \`differences\` in your report.
|
|
276638
276750
|
|
|
276639
|
-
**A
|
|
276751
|
+
**A candidate marked \`report_only\` is an observation, not work.** It sits in the code of a module other configurations call (\`report_only_reason\` says why), and restructuring that is churn for every caller: name those candidates in your \`${t("report_progress")}\` summary and open no PR for them. \`examples/\` roots are left out of every candidate list unless the operator set \`refactor_examples\`.
|
|
276640
276752
|
|
|
276641
276753
|
**Before picking, check the interface.** \`${t("module_extraction_candidates")}\` reports \`unmapped_attributes\` per candidate and a top-level \`partial_interfaces\` list: arguments the raw resources SET that the target module does not. Adopting such a module DROPS them silently \u2014 and the equivalence check cannot catch it, because once the argument is gone it is absent from both sides. Two of these are unrecoverable rather than merely wrong (\`object_lock_enabled\` cannot be set after creation; \`force_destroy\` changes deletion semantics). So: **decline the candidate, or extend the module to expose the argument and say so in the PR body.** Deleting the argument to make the shapes match is never the fix. A candidate whose \`unmapped_attributes\` is \`null\` was NOT checked \u2014 the module is external and its code is not in this repo \u2014 which is not the same as clean.
|
|
276642
276754
|
|
|
@@ -276769,7 +276881,7 @@ function remediateMode(t) {
|
|
|
276769
276881
|
|
|
276770
276882
|
4. **for the chosen group**:
|
|
276771
276883
|
- **base branch**: this run's base branch is resolved deterministically \u2014 \`${t("create_pull_request")}\` targets the \`base_branch\` input if set, else the branch the run started on, else the repository's default branch (\`main\`, or \`master\`). You do not choose it; just **omit** the \`base\` argument when opening the PR (below) and it is filled in.
|
|
276772
|
-
- **idempotency**: the remediation branch is the group's \`branch\` (\`remediate/<group-id>\`, with a \`--<base>\` suffix when the PR targets a non-default branch) \u2014 use it exactly, never a name of your own. Before doing anything, check whether that branch or an open PR for it already exists (\`${t("git")}\` / \`${t("get_pull_request")}\`). If one exists, update it rather than opening a duplicate.
|
|
276884
|
+
- **idempotency**: the remediation branch is the group's \`branch\` (\`remediate/<group-id>\`, with a \`--<base>\` suffix when the PR targets a non-default branch, or the branch of the PR already open for this group) \u2014 use it exactly, never a name of your own. Before doing anything, check whether that branch or an open PR for it already exists (\`${t("git")}\` / \`${t("get_pull_request")}\`). If one exists, update it rather than opening a duplicate.
|
|
276773
276885
|
- **branch**: create the group's \`branch\` from the **current HEAD** (the checkout that was just scanned) via \`${t("git")}\` (\`git({ command: "checkout", args: ["-b", <branch>] })\`). Do NOT switch to a different base first \u2014 branching from the scanned checkout keeps the PR diff to exactly your fix.
|
|
276774
276886
|
- **honest refusal (decide BEFORE fixing)**: if the group's concerns appear in the scan's \`refusal_candidates\` (the fix needs a human decision \u2014 narrowing an IAM wildcard, a KMS key policy, a real ingress CIDR), do **not** guess a fix that could break the stack. Instead open a structured issue (\`${t("create_issue")}\`) describing the concern, why it isn't auto-fixed, and what a human should do, and skip the PR for that group. A proven fix or an honest refusal \u2014 never a guessed, unverifiable PR.
|
|
276775
276887
|
- **propose, then let me steer (when there's no single right fix)**: distinct from honest refusal (which refuses a fix a human must *decide*), this is for a finding with **2\u20133 genuinely distinct, defensible fixes** that differ in trade-offs, not correctness (e.g. encrypt with an AWS-managed key **vs** a customer-managed KMS key; a narrow security-group rule **vs** a prefix list **vs** a VPC endpoint). When such a fork exists **and the triggering comment did not already select a strategy**, do **not** silently pick for the reviewer: via \`${t("create_issue_comment")}\` post one short comment listing the options as **A / B / C** \u2014 each a single line (what it does + its trade-off) \u2014 and ask the reviewer to reply \`${COMMENT_COMMAND} fix #<concern-id> with strategy <A|B|C>\`. Then **skip the PR for this group** this run and note it in your final report (it resumes when the reviewer replies). When the comment **did** select one (\`fix #<id> with strategy B\`, or a bare \`strategy B\` reply on the proposal thread), apply **exactly** that strategy \u2014 don't second-guess it. Reserve this for real forks in the road; a fix with one obvious correct answer just gets made.
|
|
@@ -276830,7 +276942,7 @@ This mode composes the **Remediate** and **Refactor** verbs into a single run. I
|
|
|
276830
276942
|
- **commit the fix** (\`git add\` only the changed \`*.tf\`/\`*.tfvars\`, a \`fix(tf): \u2026\` message). Do NOT push yet. This committed state is the refactor's equivalence BASELINE.
|
|
276831
276943
|
|
|
276832
276944
|
3. **REFACTOR (phase 2) \u2014 modularise on top of the committed fix**: follow the **Refactor** mode's flow:
|
|
276833
|
-
- \`${t("module_extraction_candidates")}\` / \`${t("terraform_normalization_candidates")}\` \u2192 pick one behaviour-preserving refactor; a
|
|
276945
|
+
- \`${t("module_extraction_candidates")}\` / \`${t("terraform_normalization_candidates")}\` \u2192 pick one behaviour-preserving refactor; a candidate marked \`report_only\` (it sits in the code of a module others call) is named in the summary, never proposed. Respect a pinned \`refactor_source\` if one was supplied (it constrains which module source you may use; the behaviour-altering b.4 path is only available when the operator pinned \`third-party\`).
|
|
276834
276946
|
- resolve the module source, wire the \`module\` call against its real interface (\`${t("terraform_module_interface")}\` for a local module dir, \`${t("terraform_module_lookup")}\` for a registry-sourced one), and emit a \`moved {}\` block for EVERY relocated address (\`${t("terraform_generate_moved")}\`).
|
|
276835
276947
|
- \`terraform fmt\` + \`${t("terraform_validate")}\`, then \u2014 **with the refactor edits still UNCOMMITTED** \u2014 call \`${t("terraform_equivalence_check")}\`. In this mode it diffs the working tree against the COMMITTED fix (not the run-start commit), so it measures only the refactor. It must return \`equivalent: true\` (zero uncovered moves, resource set + arguments preserved, validate + fmt clean) before you proceed; \`${t("push_branch")}\` hard-blocks an unproven one \u2014 and, once this run has added a \`moved {}\` block, it also hard-blocks a push that never ran the check at all, so abandoning the refactor means REVERTING its edits rather than leaving them in with the fix. If it can't be proven equivalent, abandon the refactor and ship the fix alone.
|
|
276836
276948
|
- **document the module (only when the \`docs\` input is enabled)**: after the equivalence check passes, call \`${t("terraform_module_docs")}\` for the module you created/adopted (pass the relocated addresses as \`moves\`). Do not hand-write docs \u2014 the tool builds from the interface, moved blocks, and equivalence verdict.
|
|
@@ -278383,15 +278495,52 @@ var Git = type({
|
|
|
278383
278495
|
args: type.string.array().describe("Additional arguments for the git command").optional()
|
|
278384
278496
|
});
|
|
278385
278497
|
function splitWords(line) {
|
|
278386
|
-
|
|
278498
|
+
const words2 = [];
|
|
278499
|
+
let word = "";
|
|
278500
|
+
let inWord = false;
|
|
278501
|
+
let quote;
|
|
278502
|
+
for (let i = 0; i < line.length; i++) {
|
|
278503
|
+
const ch = line.charAt(i);
|
|
278504
|
+
if (quote === "'") {
|
|
278505
|
+
if (ch === "'") quote = void 0;
|
|
278506
|
+
else word += ch;
|
|
278507
|
+
} else if (quote === '"') {
|
|
278508
|
+
if (ch === '"') quote = void 0;
|
|
278509
|
+
else if (ch === "\\" && i + 1 < line.length && '"\\$`\n'.includes(line.charAt(i + 1))) {
|
|
278510
|
+
i += 1;
|
|
278511
|
+
if (line.charAt(i) !== "\n") word += line.charAt(i);
|
|
278512
|
+
} else word += ch;
|
|
278513
|
+
} else if (ch === " " || ch === " ") {
|
|
278514
|
+
if (inWord) words2.push(word);
|
|
278515
|
+
word = "";
|
|
278516
|
+
inWord = false;
|
|
278517
|
+
} else if (ch === "\n") {
|
|
278518
|
+
throw new Error(
|
|
278519
|
+
"command holds an unquoted newline \u2014 pass one git command per call, and quote a multi-line message"
|
|
278520
|
+
);
|
|
278521
|
+
} else if (ch === "\\") {
|
|
278522
|
+
if (i + 1 >= line.length) throw new Error("command ends in a backslash that escapes nothing");
|
|
278523
|
+
i += 1;
|
|
278524
|
+
if (line.charAt(i) === "\n") continue;
|
|
278525
|
+
word += line.charAt(i);
|
|
278526
|
+
inWord = true;
|
|
278527
|
+
} else if (ch === "'" || ch === '"') {
|
|
278528
|
+
quote = ch;
|
|
278529
|
+
inWord = true;
|
|
278530
|
+
} else {
|
|
278531
|
+
word += ch;
|
|
278532
|
+
inWord = true;
|
|
278533
|
+
}
|
|
278534
|
+
}
|
|
278535
|
+
if (quote) throw new Error(`command has an unterminated ${quote} quote`);
|
|
278536
|
+
if (inWord) words2.push(word);
|
|
278537
|
+
return words2;
|
|
278387
278538
|
}
|
|
278388
278539
|
function normalizeGitCall(params) {
|
|
278389
|
-
|
|
278390
|
-
|
|
278391
|
-
|
|
278392
|
-
|
|
278393
|
-
else return { command: params.command, args: params.args ?? [] };
|
|
278394
|
-
const [command, ...args2] = words2[0] === "git" ? words2.slice(1) : words2;
|
|
278540
|
+
const words2 = params.command === void 0 ? [] : /^git\s/.test(params.command) ? splitWords(params.command) : [params.command];
|
|
278541
|
+
words2.push(...params.args ?? []);
|
|
278542
|
+
while (words2[0] === "git") words2.shift();
|
|
278543
|
+
const [command, ...args2] = words2;
|
|
278395
278544
|
if (command === void 0 || !/^[a-z][a-z0-9-]*$/.test(command)) {
|
|
278396
278545
|
throw new Error(
|
|
278397
278546
|
`command must be a Git subcommand such as 'status' or 'checkout' (was "${command ?? ""}")`
|
|
@@ -278577,7 +278726,7 @@ function PushTagsTool(ctx) {
|
|
|
278577
278726
|
}
|
|
278578
278727
|
|
|
278579
278728
|
// src/mcp/review.ts
|
|
278580
|
-
import { readFileSync as
|
|
278729
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
278581
278730
|
|
|
278582
278731
|
// src/mcp/findingAudit.ts
|
|
278583
278732
|
var COHERENCE_RULES = {
|
|
@@ -278827,7 +278976,7 @@ function claimsBlockingSeverity(body2) {
|
|
|
278827
278976
|
init_core3();
|
|
278828
278977
|
import { isAbsolute as isAbsolute4, resolve as resolve7 } from "node:path";
|
|
278829
278978
|
|
|
278830
|
-
// node_modules/.pnpm/@infraweaver-io+models@0.1.
|
|
278979
|
+
// node_modules/.pnpm/@infraweaver-io+models@0.1.7/node_modules/@infraweaver-io/models/dist/monotonicQuota.js
|
|
278831
278980
|
function createMonotonicQuota(params) {
|
|
278832
278981
|
const { limit, unlimited, normalize: normalize5 } = params;
|
|
278833
278982
|
let used = 0;
|
|
@@ -278852,7 +279001,7 @@ function createMonotonicQuota(params) {
|
|
|
278852
279001
|
};
|
|
278853
279002
|
}
|
|
278854
279003
|
|
|
278855
|
-
// node_modules/.pnpm/@infraweaver-io+models@0.1.
|
|
279004
|
+
// node_modules/.pnpm/@infraweaver-io+models@0.1.7/node_modules/@infraweaver-io/models/dist/costQuota.js
|
|
278856
279005
|
var CostQuotaExceededError = class extends Error {
|
|
278857
279006
|
code = "COST_QUOTA_EXCEEDED";
|
|
278858
279007
|
constructor(message2) {
|
|
@@ -278899,7 +279048,7 @@ function resolveRunCostQuota(parsed2) {
|
|
|
278899
279048
|
return parsed2 === void 0 ? DEFAULT_RUN_COST_QUOTA_USD : parsed2;
|
|
278900
279049
|
}
|
|
278901
279050
|
|
|
278902
|
-
// node_modules/.pnpm/@infraweaver-io+models@0.1.
|
|
279051
|
+
// node_modules/.pnpm/@infraweaver-io+models@0.1.7/node_modules/@infraweaver-io/models/dist/tokenQuota.js
|
|
278903
279052
|
var TokenQuotaExceededError = class extends Error {
|
|
278904
279053
|
code = "TOKEN_QUOTA_EXCEEDED";
|
|
278905
279054
|
constructor(message2) {
|
|
@@ -278909,19 +279058,16 @@ var TokenQuotaExceededError = class extends Error {
|
|
|
278909
279058
|
};
|
|
278910
279059
|
var DEFAULT_RUN_TOKEN_QUOTA = 1e7;
|
|
278911
279060
|
var RUN_TOKEN_QUOTA_INPUT = "max_run_tokens";
|
|
278912
|
-
|
|
278913
|
-
|
|
278914
|
-
|
|
278915
|
-
|
|
278916
|
-
total += v;
|
|
278917
|
-
}
|
|
278918
|
-
return Math.floor(total);
|
|
279061
|
+
var CACHE_READ_WEIGHT = 0.1;
|
|
279062
|
+
function quotaTokens(t) {
|
|
279063
|
+
const part = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : 0;
|
|
279064
|
+
return Math.floor(part(t.input) + part(t.output) + part(t.cacheWrite) + part(t.cacheRead) * CACHE_READ_WEIGHT);
|
|
278919
279065
|
}
|
|
278920
279066
|
function normalizeTotal(total) {
|
|
278921
|
-
return typeof total === "number" ? Math.max(0, Math.floor(total)) :
|
|
279067
|
+
return typeof total === "number" ? Math.max(0, Math.floor(total)) : quotaTokens(total);
|
|
278922
279068
|
}
|
|
278923
279069
|
function tokenGap(used, ceiling) {
|
|
278924
|
-
return `run token quota exhausted: ${used.toLocaleString("en-GB")} of ${ceiling.toLocaleString("en-GB")}
|
|
279070
|
+
return `run token quota exhausted: ${used.toLocaleString("en-GB")} of ${ceiling.toLocaleString("en-GB")} tokens counted against the quota (a token read from the prompt cache counts as a tenth), so the run was stopped before it finished. Its results are INCOMPLETE and must not be read as a clean assessment \u2014 a finding that would have been raised after this point was never looked for. Raise \`${RUN_TOKEN_QUOTA_INPUT}\` if the run legitimately needs more budget, or set \`${RUN_TOKEN_QUOTA_INPUT}: 0\` to remove the bound entirely. A run that reaches this limit without finishing is more often a remediation loop that cannot converge (a fix that re-breaks its own check) than a genuinely large repository.`;
|
|
278925
279071
|
}
|
|
278926
279072
|
function unlimitedTokenQuota() {
|
|
278927
279073
|
return createMonotonicQuota({
|
|
@@ -280064,6 +280210,12 @@ function parseCommentMarker(body2) {
|
|
|
280064
280210
|
return null;
|
|
280065
280211
|
}
|
|
280066
280212
|
}
|
|
280213
|
+
function findingKeysIn(body2) {
|
|
280214
|
+
return [...body2.matchAll(new RegExp(MARKER.source, "g"))].flatMap((m) => {
|
|
280215
|
+
const marker2 = parseCommentMarker(m[0]);
|
|
280216
|
+
return marker2?.kind === "finding" ? [marker2.key] : [];
|
|
280217
|
+
});
|
|
280218
|
+
}
|
|
280067
280219
|
var SUGGESTION = /```suggestion\r?\n([\s\S]*?)```/;
|
|
280068
280220
|
function suggestionText(body2) {
|
|
280069
280221
|
const m = SUGGESTION.exec(body2);
|
|
@@ -280220,23 +280372,54 @@ function computeScanDelta(input2) {
|
|
|
280220
280372
|
};
|
|
280221
280373
|
}
|
|
280222
280374
|
function markPossibleRenames(introduced, resolved, headAddresses) {
|
|
280223
|
-
const
|
|
280224
|
-
|
|
280225
|
-
|
|
280226
|
-
|
|
280375
|
+
const byResource = (findings) => {
|
|
280376
|
+
const out = /* @__PURE__ */ new Map();
|
|
280377
|
+
for (const f of [...findings].sort((a, b) => byLocation(a.concern, b.concern))) {
|
|
280378
|
+
if (f.address === null) continue;
|
|
280379
|
+
const dir = dirOf3(f.concern.location.file);
|
|
280380
|
+
const key = `${dir}|${f.address}`;
|
|
280381
|
+
const entry4 = out.get(key);
|
|
280382
|
+
if (entry4) entry4.findings.push(f);
|
|
280383
|
+
else out.set(key, { dir, address: f.address, findings: [f] });
|
|
280384
|
+
}
|
|
280385
|
+
return [...out.values()];
|
|
280386
|
+
};
|
|
280387
|
+
const vanished = byResource(resolved).filter((r) => !headAddresses(r.dir).has(r.address));
|
|
280388
|
+
const appeared = byResource(introduced);
|
|
280389
|
+
const shared = (from, to) => {
|
|
280390
|
+
const left = /* @__PURE__ */ new Map();
|
|
280391
|
+
for (const f of from.findings)
|
|
280392
|
+
left.set(ruleKey(f.concern), (left.get(ruleKey(f.concern)) ?? 0) + 1);
|
|
280393
|
+
return to.findings.filter((f) => {
|
|
280394
|
+
const n = left.get(ruleKey(f.concern)) ?? 0;
|
|
280395
|
+
if (n === 0) return false;
|
|
280396
|
+
left.set(ruleKey(f.concern), n - 1);
|
|
280397
|
+
return true;
|
|
280398
|
+
});
|
|
280399
|
+
};
|
|
280400
|
+
const order2 = (a, b) => a.dir.localeCompare(b.dir) || a.address.localeCompare(b.address);
|
|
280401
|
+
const candidates = vanished.flatMap(
|
|
280402
|
+
(from) => appeared.filter(
|
|
280403
|
+
(to) => (
|
|
280404
|
+
// a `moved` block cannot change a resource's type
|
|
280405
|
+
typeOf(from.address) === typeOf(to.address) && // renamed in place, or moved elsewhere under its own name
|
|
280406
|
+
from.dir === to.dir !== (from.address === to.address)
|
|
280407
|
+
)
|
|
280408
|
+
).map((to) => ({ from, to, findings: shared(from, to) })).filter((p) => p.findings.length > 0)
|
|
280409
|
+
);
|
|
280410
|
+
candidates.sort(
|
|
280411
|
+
(a, b) => b.findings.length - a.findings.length || order2(a.from, b.from) || order2(a.to, b.to)
|
|
280412
|
+
);
|
|
280227
280413
|
const used = /* @__PURE__ */ new Set();
|
|
280228
|
-
for (const
|
|
280229
|
-
if (
|
|
280230
|
-
|
|
280231
|
-
|
|
280232
|
-
|
|
280233
|
-
|
|
280234
|
-
|
|
280235
|
-
|
|
280236
|
-
|
|
280237
|
-
used.add(match5);
|
|
280238
|
-
finding.possiblyPreexisting = true;
|
|
280239
|
-
finding.renamedFrom = { address: match5.address, file: match5.concern.location.file };
|
|
280414
|
+
for (const { from, to, findings } of candidates) {
|
|
280415
|
+
if (used.has(from) || used.has(to)) continue;
|
|
280416
|
+
used.add(from);
|
|
280417
|
+
used.add(to);
|
|
280418
|
+
const file2 = from.findings[0]?.concern.location.file;
|
|
280419
|
+
for (const finding of findings) {
|
|
280420
|
+
finding.possiblyPreexisting = true;
|
|
280421
|
+
finding.renamedFrom = { address: from.address, file: file2 };
|
|
280422
|
+
}
|
|
280240
280423
|
}
|
|
280241
280424
|
}
|
|
280242
280425
|
function typeOf(address) {
|
|
@@ -280505,39 +280688,115 @@ function formatDuplicateCommentsNote(duplicates) {
|
|
|
280505
280688
|
var MAX_DUPLICATE_COMMENT_LINES = 50;
|
|
280506
280689
|
|
|
280507
280690
|
// src/mcp/reviewCommentLimit.ts
|
|
280508
|
-
var
|
|
280691
|
+
var MAX_NOTE_CHARS = 3e4;
|
|
280692
|
+
var TRAILER_RESERVE = 400;
|
|
280509
280693
|
var PROVEN_MARK = "\u2705 **Proven by re-scan**";
|
|
280510
|
-
|
|
280694
|
+
var SEVERITY_LEVEL = {
|
|
280695
|
+
critical: 0,
|
|
280696
|
+
high: 1,
|
|
280697
|
+
medium: 2,
|
|
280698
|
+
low: 3,
|
|
280699
|
+
info: 4
|
|
280700
|
+
};
|
|
280701
|
+
var MARKER_LEVEL = { "\u{1F6A8}": 1, "\u26A0\uFE0F": 2, "\u26A0": 2, "\u2139\uFE0F": 3, \u2139: 3 };
|
|
280702
|
+
var UNMARKED_LEVEL = 2;
|
|
280703
|
+
function rank(c, severity) {
|
|
280511
280704
|
const body2 = c.body ?? "";
|
|
280512
|
-
const
|
|
280513
|
-
|
|
280514
|
-
return severity + (body2.includes(PROVEN_MARK) ? 0 : 1);
|
|
280705
|
+
const level = severity ? SEVERITY_LEVEL[severity] : MARKER_LEVEL[leadingMarker(body2) ?? ""] ?? UNMARKED_LEVEL;
|
|
280706
|
+
return level * 2 + (body2.includes(PROVEN_MARK) ? 0 : 1);
|
|
280515
280707
|
}
|
|
280516
|
-
function limitInlineComments(comments, limit) {
|
|
280708
|
+
function limitInlineComments(comments, limit, severityOf) {
|
|
280517
280709
|
if (!limit || comments.length <= limit) return { kept: [...comments], overflow: [] };
|
|
280518
280710
|
const keep = new Set(
|
|
280519
|
-
comments.map((c, i) => ({ i, r: rank(c) })).sort((a, b) => a.r - b.r || a.i - b.i).slice(0, limit).map(({ i }) => i)
|
|
280711
|
+
comments.map((c, i) => ({ i, r: rank(c, severityOf?.(c)) })).sort((a, b) => a.r - b.r || a.i - b.i).slice(0, limit).map(({ i }) => i)
|
|
280520
280712
|
);
|
|
280521
280713
|
return {
|
|
280522
280714
|
kept: comments.filter((_, i) => keep.has(i)),
|
|
280523
280715
|
overflow: comments.filter((_, i) => !keep.has(i))
|
|
280524
280716
|
};
|
|
280525
280717
|
}
|
|
280526
|
-
|
|
280718
|
+
var escapeHtml = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
280719
|
+
var whereOf = (c) => c.line ? `${c.path}:${c.line}` : c.path;
|
|
280720
|
+
function closesItself(body2) {
|
|
280721
|
+
const occurrences = (re) => body2.match(re)?.length ?? 0;
|
|
280722
|
+
const fences = body2.split("\n").filter((l) => /^\s*(```|~~~)/.test(l)).length;
|
|
280723
|
+
return fences % 2 === 0 && occurrences(/<details\b/gi) === occurrences(/<\/details\s*>/gi) && occurrences(/<!--/g) === occurrences(/-->/g);
|
|
280724
|
+
}
|
|
280725
|
+
function asText(body2) {
|
|
280726
|
+
const longest = Math.max(0, ...(body2.match(/`+/g) ?? []).map((run2) => run2.length));
|
|
280727
|
+
const fence = "`".repeat(Math.max(3, longest + 1));
|
|
280728
|
+
return `${fence}text
|
|
280729
|
+
${body2}
|
|
280730
|
+
${fence}`;
|
|
280731
|
+
}
|
|
280732
|
+
function renderWhole(c, linkOf) {
|
|
280733
|
+
const where4 = escapeHtml(whereOf(c));
|
|
280734
|
+
const gist = gistOf(c.body);
|
|
280735
|
+
const href = linkOf?.(c);
|
|
280736
|
+
const body2 = c.body ?? "";
|
|
280737
|
+
return [
|
|
280738
|
+
`<details><summary><code>${where4}</code>${gist ? ` \u2014 ${gist}` : ""}</summary>`,
|
|
280739
|
+
...href ? [`<a href="${escapeHtml(href)}">${where4}</a>`] : [],
|
|
280740
|
+
...body2 ? [closesItself(body2) ? body2 : asText(body2)] : [],
|
|
280741
|
+
"</details>"
|
|
280742
|
+
].join("\n\n");
|
|
280743
|
+
}
|
|
280744
|
+
function renderBrief(c) {
|
|
280745
|
+
const gist = gistOf(c.body);
|
|
280746
|
+
const markers = findingKeysIn(c.body ?? "").map(
|
|
280747
|
+
(key) => renderCommentMarker({ kind: "finding", key, proven: false })
|
|
280748
|
+
);
|
|
280749
|
+
return `- \`${whereOf(c).replace(/`/g, "'")}\`${gist ? ` \u2014 ${gist}` : ""}${markers.map((m) => ` ${m}`).join("")}`;
|
|
280750
|
+
}
|
|
280751
|
+
function formatOverflowNote(overflow, limit, linkOf) {
|
|
280527
280752
|
if (overflow.length === 0) return "";
|
|
280528
|
-
const
|
|
280529
|
-
const where4 = c.line ? `${c.path}:${c.line}` : c.path;
|
|
280530
|
-
const gist = gistOf(c.body);
|
|
280531
|
-
return `- \`${where4.replace(/`/g, "'")}\`${gist ? ` \u2014 ${gist}` : ""}`;
|
|
280532
|
-
});
|
|
280533
|
-
const rest = overflow.length - shown.length;
|
|
280534
|
-
if (rest > 0) shown.push(`- \u2026and ${rest} more not shown`);
|
|
280535
|
-
return `
|
|
280753
|
+
const header = `
|
|
280536
280754
|
|
|
280537
280755
|
---
|
|
280538
280756
|
|
|
280539
|
-
**Note:** this review posts at most ${limit} inline comments (\`review_comment_limit\`), so ${overflow.length} more ${overflow.length === 1 ? "is" : "are"} listed here instead
|
|
280540
|
-
|
|
280757
|
+
**Note:** this review posts at most ${limit} inline comments (\`review_comment_limit\`), so ${overflow.length} more ${overflow.length === 1 ? "is" : "are"} listed here instead:`;
|
|
280758
|
+
const SEP = 2;
|
|
280759
|
+
let room = MAX_NOTE_CHARS - TRAILER_RESERVE - header.length;
|
|
280760
|
+
const items = [];
|
|
280761
|
+
for (const c of overflow) {
|
|
280762
|
+
const brief2 = renderBrief(c);
|
|
280763
|
+
if (brief2.length + SEP > room) break;
|
|
280764
|
+
items.push(brief2);
|
|
280765
|
+
room -= brief2.length + SEP;
|
|
280766
|
+
}
|
|
280767
|
+
let brief = items.length;
|
|
280768
|
+
for (const [i, c] of overflow.slice(0, items.length).entries()) {
|
|
280769
|
+
const whole = renderWhole(c, linkOf);
|
|
280770
|
+
const extra = whole.length - items[i].length;
|
|
280771
|
+
if (extra > room) continue;
|
|
280772
|
+
items[i] = whole;
|
|
280773
|
+
room -= extra;
|
|
280774
|
+
brief--;
|
|
280775
|
+
}
|
|
280776
|
+
const omitted = overflow.length - items.length;
|
|
280777
|
+
if (omitted > 0) items.push(`- \u2026and ${omitted} more not shown`);
|
|
280778
|
+
const cut = [
|
|
280779
|
+
brief > 0 ? `${brief} of them ${brief === 1 ? "is" : "are"} shown by place and first line only` : "",
|
|
280780
|
+
omitted > 0 ? `${omitted} ${omitted === 1 ? "is" : "are"} not shown at all` : ""
|
|
280781
|
+
].filter(Boolean);
|
|
280782
|
+
if (cut.length > 0) {
|
|
280783
|
+
items.push(`${cut.join(" and ")}, to keep this review within GitHub's size limit.`);
|
|
280784
|
+
}
|
|
280785
|
+
return `${header}
|
|
280786
|
+
|
|
280787
|
+
${items.join("\n\n")}`;
|
|
280788
|
+
}
|
|
280789
|
+
function foldedFindingsStillIntroduced(input2) {
|
|
280790
|
+
const folded = new Set(
|
|
280791
|
+
input2.reviews.flatMap(
|
|
280792
|
+
(r) => r.body && isOwnReviewComment(r.user, r.body) ? findingKeysIn(r.body) : []
|
|
280793
|
+
)
|
|
280794
|
+
);
|
|
280795
|
+
if (folded.size === 0) return [];
|
|
280796
|
+
const dismissed = new Set(input2.dismissed.map((d) => d.finding_id));
|
|
280797
|
+
return input2.delta.introduced.filter(
|
|
280798
|
+
(f) => folded.has(findingKey(f)) && !dismissed.has(f.concern.id)
|
|
280799
|
+
);
|
|
280541
280800
|
}
|
|
280542
280801
|
|
|
280543
280802
|
// src/mcp/reviewComments.ts
|
|
@@ -281368,7 +281627,8 @@ function deltaVerdict(delta, requiredControls) {
|
|
|
281368
281627
|
return {
|
|
281369
281628
|
pass: gate.pass && required3.length === 0,
|
|
281370
281629
|
gating: gate.gating.length,
|
|
281371
|
-
required: required3.length
|
|
281630
|
+
required: required3.length,
|
|
281631
|
+
blocking: (/* @__PURE__ */ new Set([...gate.gating, ...required3])).size
|
|
281372
281632
|
};
|
|
281373
281633
|
}
|
|
281374
281634
|
function failsGate(finding, requiredControls) {
|
|
@@ -281495,7 +281755,7 @@ function where2(f) {
|
|
|
281495
281755
|
function renderReviewVerdict(input2) {
|
|
281496
281756
|
const { delta, verdict: verdict2 } = input2;
|
|
281497
281757
|
const introduced = delta.introduced.length;
|
|
281498
|
-
const blocking = verdict2
|
|
281758
|
+
const { blocking } = verdict2;
|
|
281499
281759
|
const renamedBlocking = delta.introduced.filter(
|
|
281500
281760
|
(f) => f.possiblyPreexisting && failsGate(f, [...input2.requiredControls ?? []])
|
|
281501
281761
|
).length;
|
|
@@ -281604,7 +281864,7 @@ import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync16, rmSync as
|
|
|
281604
281864
|
import { join as join28, posix as posix8 } from "node:path";
|
|
281605
281865
|
|
|
281606
281866
|
// src/mcp/terraform/lineage.ts
|
|
281607
|
-
import { createHash as
|
|
281867
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
281608
281868
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
281609
281869
|
import { join as join27 } from "node:path";
|
|
281610
281870
|
function repoFileReader(cwd) {
|
|
@@ -281617,7 +281877,7 @@ function repoFileReader(cwd) {
|
|
|
281617
281877
|
};
|
|
281618
281878
|
}
|
|
281619
281879
|
function lineageKeyOf(c, address) {
|
|
281620
|
-
return
|
|
281880
|
+
return createHash9("sha1").update(`${c.source}|${bareRuleOf(c.source, c.rule_id)}|${c.location.file}|${address ?? ""}`).digest("hex").slice(0, 16);
|
|
281621
281881
|
}
|
|
281622
281882
|
function lineageResolver(read3) {
|
|
281623
281883
|
const files = /* @__PURE__ */ new Map();
|
|
@@ -281789,7 +282049,7 @@ function apply(worktree, path15, cs) {
|
|
|
281789
282049
|
|
|
281790
282050
|
// src/mcp/terraform/gateScan.ts
|
|
281791
282051
|
import { existsSync as existsSync7, mkdtempSync as mkdtempSync3, rmSync as rmSync6 } from "node:fs";
|
|
281792
|
-
import { join as
|
|
282052
|
+
import { join as join33, posix as posix10 } from "node:path";
|
|
281793
282053
|
|
|
281794
282054
|
// src/mcp/terraform/coverage.ts
|
|
281795
282055
|
function bandOf(group2, concerns, signals) {
|
|
@@ -282227,6 +282487,68 @@ function dedupeCrossScanner(concerns) {
|
|
|
282227
282487
|
return [...merged, ...passthrough];
|
|
282228
282488
|
}
|
|
282229
282489
|
|
|
282490
|
+
// src/mcp/terraform/verifySites.ts
|
|
282491
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
282492
|
+
import { join as join29 } from "node:path";
|
|
282493
|
+
function fileReader(cwd) {
|
|
282494
|
+
const cache3 = /* @__PURE__ */ new Map();
|
|
282495
|
+
return (file2) => {
|
|
282496
|
+
if (!cache3.has(file2)) {
|
|
282497
|
+
let text;
|
|
282498
|
+
try {
|
|
282499
|
+
text = readFileSync17(join29(cwd, file2), "utf8");
|
|
282500
|
+
} catch {
|
|
282501
|
+
text = null;
|
|
282502
|
+
}
|
|
282503
|
+
cache3.set(file2, text);
|
|
282504
|
+
}
|
|
282505
|
+
return cache3.get(file2) ?? null;
|
|
282506
|
+
};
|
|
282507
|
+
}
|
|
282508
|
+
function siteOf(c, read3) {
|
|
282509
|
+
const text = read3(c.location.file);
|
|
282510
|
+
return text === null ? null : resourceAddressAt(text, c.location.line);
|
|
282511
|
+
}
|
|
282512
|
+
function recordConcernSites(session, concerns, cwd, linesMatchTree) {
|
|
282513
|
+
const read3 = fileReader(cwd);
|
|
282514
|
+
session.siteById ??= /* @__PURE__ */ new Map();
|
|
282515
|
+
session.firstSitesByKey ??= /* @__PURE__ */ new Map();
|
|
282516
|
+
const first = session.firstSitesByKey;
|
|
282517
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
282518
|
+
for (const c of concerns) {
|
|
282519
|
+
const site = linesMatchTree ? siteOf(c, read3) : null;
|
|
282520
|
+
const prior = session.siteById.get(c.id);
|
|
282521
|
+
session.siteById.set(c.id, prior === void 0 || prior === site ? site : null);
|
|
282522
|
+
if (!linesMatchTree) continue;
|
|
282523
|
+
const key = concernKeyOf(c);
|
|
282524
|
+
if (first.has(key)) continue;
|
|
282525
|
+
const sites = fresh.get(key) ?? /* @__PURE__ */ new Set();
|
|
282526
|
+
sites.add(site);
|
|
282527
|
+
fresh.set(key, sites);
|
|
282528
|
+
}
|
|
282529
|
+
for (const [key, sites] of fresh) first.set(key, sites);
|
|
282530
|
+
}
|
|
282531
|
+
function resolvedAtSite(params) {
|
|
282532
|
+
const firingByKey = /* @__PURE__ */ new Map();
|
|
282533
|
+
for (const c of params.current) {
|
|
282534
|
+
const list = firingByKey.get(c.key) ?? [];
|
|
282535
|
+
list.push(c.site);
|
|
282536
|
+
firingByKey.set(c.key, list);
|
|
282537
|
+
}
|
|
282538
|
+
const out = [];
|
|
282539
|
+
for (const r of params.requested) {
|
|
282540
|
+
if (r.site === null || r.file === void 0) continue;
|
|
282541
|
+
const firing = firingByKey.get(r.key) ?? [];
|
|
282542
|
+
const known = params.firstSites.get(r.key);
|
|
282543
|
+
if (known === void 0) continue;
|
|
282544
|
+
if (firing.some((s) => s === null || !known.has(s))) continue;
|
|
282545
|
+
if (firing.includes(r.site)) continue;
|
|
282546
|
+
if (!params.declared(r.file).has(r.site)) continue;
|
|
282547
|
+
out.push(r.id);
|
|
282548
|
+
}
|
|
282549
|
+
return out;
|
|
282550
|
+
}
|
|
282551
|
+
|
|
282230
282552
|
// src/mcp/terraform/concernResult.ts
|
|
282231
282553
|
function annotateConcerns(rawConcerns, opts) {
|
|
282232
282554
|
const inScope = opts.inScope ?? (() => true);
|
|
@@ -282253,6 +282575,7 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282253
282575
|
fullBaseline.map((c) => concernKeyOf(c))
|
|
282254
282576
|
);
|
|
282255
282577
|
recordConcernKeys(session, fullBaseline);
|
|
282578
|
+
recordConcernSites(session, fullBaseline, opts.cwd, opts.linesMatchTree ?? false);
|
|
282256
282579
|
session.baselineFmtDriftFiles = union3(
|
|
282257
282580
|
session.baselineFmtDriftFiles,
|
|
282258
282581
|
fullBaseline.filter((c) => c.source === "terraform-fmt").map((c) => c.location.file)
|
|
@@ -282267,13 +282590,13 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282267
282590
|
active,
|
|
282268
282591
|
opts.autonomyThreshold
|
|
282269
282592
|
);
|
|
282270
|
-
const
|
|
282271
|
-
|
|
282272
|
-
|
|
282273
|
-
);
|
|
282274
|
-
const groups2 = (opts.priority ? prioritizeGroups(annotatedGroups, active, opts.priority) : annotatedGroups).map((g) => ({ ...g, branch: `remediate/${g.id}${suffix2}` }));
|
|
282593
|
+
const base = remediationBaseOf(ctx);
|
|
282594
|
+
const defaultBranch = ctx.repo?.data.default_branch?.trim() || void 0;
|
|
282595
|
+
const branchFor = (id) => remediationBranchFor(id, base, defaultBranch, opts.openRemediationPrs);
|
|
282596
|
+
const groups2 = (opts.priority ? prioritizeGroups(annotatedGroups, active, opts.priority) : annotatedGroups).map((g) => ({ ...g, branch: branchFor(g.id) }));
|
|
282275
282597
|
const planned = planBatches(groups2);
|
|
282276
|
-
const
|
|
282598
|
+
const batchId = planned.batch_branch ? groupIdFromBranch(planned.batch_branch) : null;
|
|
282599
|
+
const batchPlan = batchId ? { ...planned, batch_branch: branchFor(batchId) } : planned;
|
|
282277
282600
|
const bySeverity = {};
|
|
282278
282601
|
for (const c of active) bySeverity[c.severity] = (bySeverity[c.severity] ?? 0) + 1;
|
|
282279
282602
|
return {
|
|
@@ -282289,7 +282612,7 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282289
282612
|
|
|
282290
282613
|
// src/mcp/terraform/initArtefacts.ts
|
|
282291
282614
|
import { rmSync as rmSync4 } from "node:fs";
|
|
282292
|
-
import { join as
|
|
282615
|
+
import { join as join30, posix as posix9 } from "node:path";
|
|
282293
282616
|
var INIT_ARTEFACTS = /* @__PURE__ */ new Set([".terraform", ".terraform.lock.hcl"]);
|
|
282294
282617
|
function initArtefacts(cwd) {
|
|
282295
282618
|
const r = run("git", ["status", "--porcelain=v1", "-z", "--untracked-files=normal"], cwd);
|
|
@@ -282312,7 +282635,7 @@ function removeNewInitArtefacts(cwd, before, by) {
|
|
|
282312
282635
|
const created = [...after?.untracked ?? []].filter((p) => !before.untracked.has(p));
|
|
282313
282636
|
const changed = [...after?.modifiedLocks ?? []].filter((p) => !before.modifiedLocks.has(p));
|
|
282314
282637
|
if (!top || created.length + changed.length === 0) return;
|
|
282315
|
-
for (const p of created) rmSync4(
|
|
282638
|
+
for (const p of created) rmSync4(join30(top, p), { recursive: true, force: true });
|
|
282316
282639
|
if (changed.length > 0) run("git", ["checkout", "--", ...changed], top);
|
|
282317
282640
|
resetTerraformInitCache();
|
|
282318
282641
|
log2.info(
|
|
@@ -282321,8 +282644,8 @@ function removeNewInitArtefacts(cwd, before, by) {
|
|
|
282321
282644
|
}
|
|
282322
282645
|
|
|
282323
282646
|
// src/mcp/terraform/secretScan.ts
|
|
282324
|
-
import { readFileSync as
|
|
282325
|
-
import { join as
|
|
282647
|
+
import { readFileSync as readFileSync18, rmSync as rmSync5 } from "node:fs";
|
|
282648
|
+
import { join as join31 } from "node:path";
|
|
282326
282649
|
function parseBetterleaksReport(json5, prefix2 = "") {
|
|
282327
282650
|
const doc = JSON.parse(json5);
|
|
282328
282651
|
if (Array.isArray(doc) || !doc || typeof doc !== "object" || !("findings" in doc)) {
|
|
@@ -282356,7 +282679,7 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282356
282679
|
const top = run("git", ["rev-parse", "--show-toplevel"], cwd).stdout.trim();
|
|
282357
282680
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd).stdout.trim();
|
|
282358
282681
|
if (!top) return { ran: false, reason: "not a git checkout", concerns: [] };
|
|
282359
|
-
const report2 =
|
|
282682
|
+
const report2 = join31(tmp, `betterleaks-${process.pid}.json`);
|
|
282360
282683
|
try {
|
|
282361
282684
|
const r = await runAsync(
|
|
282362
282685
|
"betterleaks",
|
|
@@ -282379,7 +282702,7 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282379
282702
|
const why = (r.stderr || r.stdout).trim().split("\n").pop() ?? "";
|
|
282380
282703
|
let parsed2;
|
|
282381
282704
|
try {
|
|
282382
|
-
parsed2 = parseBetterleaksReport(
|
|
282705
|
+
parsed2 = parseBetterleaksReport(readFileSync18(report2, "utf-8"), prefix2);
|
|
282383
282706
|
} catch (error63) {
|
|
282384
282707
|
const reason = r.status !== 0 ? `betterleaks exited ${r.status}: ${why}` : `${error63}`;
|
|
282385
282708
|
return { ran: false, reason, concerns: [] };
|
|
@@ -282394,8 +282717,8 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282394
282717
|
}
|
|
282395
282718
|
|
|
282396
282719
|
// src/mcp/terraform/tools/scan.ts
|
|
282397
|
-
import { readFileSync as
|
|
282398
|
-
import { join as
|
|
282720
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
282721
|
+
import { join as join32 } from "node:path";
|
|
282399
282722
|
|
|
282400
282723
|
// src/mcp/terraform/noiseProfile.ts
|
|
282401
282724
|
var MIN_DISMISSAL_REPOS = 3;
|
|
@@ -282569,7 +282892,9 @@ async function runScan(ctx, {
|
|
|
282569
282892
|
grouping,
|
|
282570
282893
|
autonomyThreshold,
|
|
282571
282894
|
inScope,
|
|
282572
|
-
priority
|
|
282895
|
+
priority,
|
|
282896
|
+
openRemediationPrs: await listOpenRemediationPrs(ctx),
|
|
282897
|
+
linesMatchTree: true
|
|
282573
282898
|
}
|
|
282574
282899
|
);
|
|
282575
282900
|
const { active, suppressed, groups: groups2, batchPlan, bySeverity: by_severity } = result;
|
|
@@ -282581,7 +282906,7 @@ async function runScan(ctx, {
|
|
|
282581
282906
|
outcomes.flatMap((o) => o.concerns),
|
|
282582
282907
|
(rel) => {
|
|
282583
282908
|
try {
|
|
282584
|
-
return
|
|
282909
|
+
return readFileSync19(join32(cwd, rel), "utf-8");
|
|
282585
282910
|
} catch {
|
|
282586
282911
|
return null;
|
|
282587
282912
|
}
|
|
@@ -282733,8 +283058,8 @@ function checkOutBase(cwd, pr, tmp) {
|
|
|
282733
283058
|
}
|
|
282734
283059
|
const mergeBase = run("git", ["merge-base", pr.baseSha, "HEAD"], cwd).stdout.trim() || pr.baseSha;
|
|
282735
283060
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd).stdout.trim();
|
|
282736
|
-
const parent = mkdtempSync3(
|
|
282737
|
-
const worktree =
|
|
283061
|
+
const parent = mkdtempSync3(join33(tmp, "scan-delta-base-"));
|
|
283062
|
+
const worktree = join33(parent, "wt");
|
|
282738
283063
|
if (run("git", ["worktree", "add", "--detach", worktree, mergeBase], cwd).status !== 0) {
|
|
282739
283064
|
rmSync6(parent, { recursive: true, force: true });
|
|
282740
283065
|
log2.warning("\xBB scan delta: could not check out the base \u2014 every finding is treated as new.");
|
|
@@ -282742,7 +283067,7 @@ function checkOutBase(cwd, pr, tmp) {
|
|
|
282742
283067
|
}
|
|
282743
283068
|
return {
|
|
282744
283069
|
mergeBase,
|
|
282745
|
-
cwd: prefix2 ?
|
|
283070
|
+
cwd: prefix2 ? join33(worktree, prefix2) : worktree,
|
|
282746
283071
|
close: () => {
|
|
282747
283072
|
run("git", ["worktree", "remove", "--force", worktree], cwd);
|
|
282748
283073
|
rmSync6(parent, { recursive: true, force: true });
|
|
@@ -283210,6 +283535,22 @@ function CreatePullRequestReviewTool(ctx) {
|
|
|
283210
283535
|
`cannot approve: ${outstanding} unresolved ${PRODUCT_NAME} review thread(s) still open on this PR. approval requires every prior ${PRODUCT_NAME} finding to be resolved, not just the latest commits to be clean. inspect them with \`${listRef}\`; for each thread the current code genuinely addresses, reply then call \`${resolveRef2}\`, and retry this approval. if any thread is a real outstanding issue, do NOT approve \u2014 submit a non-approving review (omit \`approved\`, or set \`request_changes\` for a blocking one) that covers it instead.`
|
|
283211
283536
|
);
|
|
283212
283537
|
}
|
|
283538
|
+
if (delta) {
|
|
283539
|
+
const reviews = await ctx.octokit.paginate(ctx.octokit.rest.pulls.listReviews, {
|
|
283540
|
+
owner: ctx.repo.owner,
|
|
283541
|
+
repo: ctx.repo.name,
|
|
283542
|
+
pull_number,
|
|
283543
|
+
per_page: 100
|
|
283544
|
+
});
|
|
283545
|
+
const folded = foldedFindingsStillIntroduced({ reviews, delta, dismissed });
|
|
283546
|
+
if (folded.length > 0) {
|
|
283547
|
+
throw new Error(
|
|
283548
|
+
`cannot approve: ${folded.length} introduced finding(s) an earlier ${PRODUCT_NAME} review listed in its body (past \`review_comment_limit\`, so with no thread to resolve) are still introduced by this head: ` + folded.slice(0, 20).map(
|
|
283549
|
+
(f) => `${f.concern.id} (${f.concern.rule_id} at ${f.concern.location.file}:${f.concern.location.line ?? "?"})`
|
|
283550
|
+
).join(", ") + `. approval requires every prior ${PRODUCT_NAME} finding to be addressed. if one genuinely needs no change, list it in \`dismissed\` with the reason and retry; otherwise do NOT approve \u2014 submit a non-approving review that covers it.`
|
|
283551
|
+
);
|
|
283552
|
+
}
|
|
283553
|
+
}
|
|
283213
283554
|
}
|
|
283214
283555
|
const skip = reviewSkipDecision({
|
|
283215
283556
|
approved: approved ?? false,
|
|
@@ -283316,6 +283657,7 @@ ${formatReanchoredNote(reanchored.moved)}`
|
|
|
283316
283657
|
params.event = event;
|
|
283317
283658
|
}
|
|
283318
283659
|
const proofs = delta ? await proveReviewSuggestions(ctx, auditedComments) : /* @__PURE__ */ new Map();
|
|
283660
|
+
const findingSeverity = /* @__PURE__ */ new Map();
|
|
283319
283661
|
const reviewComments = auditedComments.map((comment, index) => {
|
|
283320
283662
|
let commentBody = fixDoubleEscapedString(comment.body || "");
|
|
283321
283663
|
if (comment.suggestion !== void 0) {
|
|
@@ -283357,6 +283699,9 @@ ${marker2}`;
|
|
|
283357
283699
|
reviewComment.start_line = comment.start_line;
|
|
283358
283700
|
reviewComment.start_side = side;
|
|
283359
283701
|
}
|
|
283702
|
+
if (comment.provenance?.kind === "scanner") {
|
|
283703
|
+
findingSeverity.set(reviewComment, comment.provenance.finding.concern.severity);
|
|
283704
|
+
}
|
|
283360
283705
|
return reviewComment;
|
|
283361
283706
|
});
|
|
283362
283707
|
let droppedComments = [];
|
|
@@ -283392,7 +283737,11 @@ ${marker2}`;
|
|
|
283392
283737
|
`withholding ${duplicateComments.length}/${reviewComments.length} inline comment(s) that duplicate open review threads`
|
|
283393
283738
|
);
|
|
283394
283739
|
}
|
|
283395
|
-
const limited = limitInlineComments(
|
|
283740
|
+
const limited = limitInlineComments(
|
|
283741
|
+
deduped.kept,
|
|
283742
|
+
ctx.payload.reviewCommentLimit,
|
|
283743
|
+
(c) => findingSeverity.get(c)
|
|
283744
|
+
);
|
|
283396
283745
|
overflowComments = limited.overflow;
|
|
283397
283746
|
if (overflowComments.length > 0) {
|
|
283398
283747
|
log2.info(
|
|
@@ -283424,7 +283773,13 @@ ${marker2}`;
|
|
|
283424
283773
|
body2 = body2 ? body2 + note : note.replace(/^\n\n/, "");
|
|
283425
283774
|
}
|
|
283426
283775
|
if (overflowComments.length > 0) {
|
|
283427
|
-
const
|
|
283776
|
+
const server = process.env.GITHUB_SERVER_URL || "https://github.com";
|
|
283777
|
+
const commit = params.commit_id;
|
|
283778
|
+
const note = formatOverflowNote(
|
|
283779
|
+
overflowComments,
|
|
283780
|
+
ctx.payload.reviewCommentLimit,
|
|
283781
|
+
commit ? (c) => `${server}/${ctx.repo.owner}/${ctx.repo.name}/blob/${commit}/${c.path.split("/").map(encodeURIComponent).join("/")}${c.line && c.side !== "LEFT" ? `#L${c.line}` : ""}` : void 0
|
|
283782
|
+
);
|
|
283428
283783
|
body2 = body2 ? body2 + note : note.replace(/^\n\n/, "");
|
|
283429
283784
|
}
|
|
283430
283785
|
let reproved = 0;
|
|
@@ -283677,7 +284032,7 @@ ${coverageState.lastBreakdown}`
|
|
|
283677
284032
|
}
|
|
283678
284033
|
function readReviewedFile(path15) {
|
|
283679
284034
|
try {
|
|
283680
|
-
return
|
|
284035
|
+
return readFileSync20(resolveWithinCwd(resolveRepoRoot(), path15), "utf-8");
|
|
283681
284036
|
} catch {
|
|
283682
284037
|
return null;
|
|
283683
284038
|
}
|
|
@@ -283992,7 +284347,7 @@ function fastForwardDiff(params, exec2) {
|
|
|
283992
284347
|
|
|
283993
284348
|
// src/utils/prompt/changeImpact.ts
|
|
283994
284349
|
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
283995
|
-
import { join as
|
|
284350
|
+
import { join as join34 } from "node:path";
|
|
283996
284351
|
var MAX_ATOMS = 20;
|
|
283997
284352
|
var MAX_REFS_PER_ATOM = 6;
|
|
283998
284353
|
var MAX_EXCERPT = 160;
|
|
@@ -284172,7 +284527,7 @@ function createChangeImpactArtifact(params) {
|
|
|
284172
284527
|
fileCount: params.files.length,
|
|
284173
284528
|
lookupError
|
|
284174
284529
|
});
|
|
284175
|
-
const path15 =
|
|
284530
|
+
const path15 = join34(
|
|
284176
284531
|
params.tmpdir,
|
|
284177
284532
|
`pr-${params.pullNumber}-${params.headSha.slice(0, 7)}-impact.md`
|
|
284178
284533
|
);
|
|
@@ -284192,7 +284547,7 @@ function createChangeImpactArtifact(params) {
|
|
|
284192
284547
|
import { execFileSync, execSync as execSync2 } from "node:child_process";
|
|
284193
284548
|
import { mkdtempSync as mkdtempSync4, readdirSync as readdirSync5, realpathSync as realpathSync4, unlinkSync as unlinkSync2 } from "node:fs";
|
|
284194
284549
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
284195
|
-
import { join as
|
|
284550
|
+
import { join as join35 } from "node:path";
|
|
284196
284551
|
|
|
284197
284552
|
// src/utils/github/ghaCore.ts
|
|
284198
284553
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
@@ -284215,7 +284570,7 @@ var TEMP_DIR_STATE_KEY = "infraweaver_temp_dir";
|
|
|
284215
284570
|
|
|
284216
284571
|
// src/utils/setup/setup.ts
|
|
284217
284572
|
function createTempDirectory() {
|
|
284218
|
-
const sharedTempDir = mkdtempSync4(
|
|
284573
|
+
const sharedTempDir = mkdtempSync4(join35(tmpdir2(), `${PRODUCT_SLUG}-`));
|
|
284219
284574
|
process.env.INFRAWEAVER_TEMP_DIR = sharedTempDir;
|
|
284220
284575
|
saveState2(TEMP_DIR_STATE_KEY, sharedTempDir);
|
|
284221
284576
|
log2.info(`\xBB created temp dir at ${sharedTempDir}`);
|
|
@@ -284261,13 +284616,13 @@ function wipeRunnerLeakSurface() {
|
|
|
284261
284616
|
return [];
|
|
284262
284617
|
}
|
|
284263
284618
|
};
|
|
284264
|
-
const fileCommandsDir =
|
|
284619
|
+
const fileCommandsDir = join35(runnerTemp, "_runner_file_commands");
|
|
284265
284620
|
for (const entry4 of listDir(fileCommandsDir)) {
|
|
284266
|
-
tryUnlink(
|
|
284621
|
+
tryUnlink(join35(fileCommandsDir, entry4));
|
|
284267
284622
|
}
|
|
284268
284623
|
for (const entry4 of listDir(runnerTemp)) {
|
|
284269
284624
|
if (entry4.endsWith(".sh") || /^git-credentials-.*\.config$/.test(entry4)) {
|
|
284270
|
-
tryUnlink(
|
|
284625
|
+
tryUnlink(join35(runnerTemp, entry4));
|
|
284271
284626
|
}
|
|
284272
284627
|
}
|
|
284273
284628
|
if (wiped.length > 0) {
|
|
@@ -284436,7 +284791,7 @@ function formatFilesWithLineNumbers(files) {
|
|
|
284436
284791
|
}
|
|
284437
284792
|
const tocLines = [`## Files (${files.length})`];
|
|
284438
284793
|
for (const entry4 of tocEntries) {
|
|
284439
|
-
const anchor2 =
|
|
284794
|
+
const anchor2 = createHash10("sha256").update(entry4.filename).digest("hex");
|
|
284440
284795
|
tocLines.push(
|
|
284441
284796
|
`- ${entry4.filename} \u2192 lines ${entry4.startLine}-${entry4.endLine} \xB7 diff-${anchor2}`
|
|
284442
284797
|
);
|
|
@@ -284766,7 +285121,7 @@ function CheckoutPrTool(ctx) {
|
|
|
284766
285121
|
headSha: ctx.toolState.checkoutSha
|
|
284767
285122
|
});
|
|
284768
285123
|
if (incremental) {
|
|
284769
|
-
incrementalDiffPath =
|
|
285124
|
+
incrementalDiffPath = join36(
|
|
284770
285125
|
tempDir,
|
|
284771
285126
|
`pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
|
|
284772
285127
|
);
|
|
@@ -284780,7 +285135,7 @@ function CheckoutPrTool(ctx) {
|
|
|
284780
285135
|
const diffPreview = formatResult.content.split("\n").slice(0, 100).join("\n");
|
|
284781
285136
|
log2.debug(`formatted diff preview (first 100 lines):
|
|
284782
285137
|
${diffPreview}`);
|
|
284783
|
-
const diffPath =
|
|
285138
|
+
const diffPath = join36(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
284784
285139
|
writeFileSync10(diffPath, formatResult.content);
|
|
284785
285140
|
log2.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
284786
285141
|
ctx.toolState.diffCoverage = createDiffCoverageState({
|
|
@@ -284921,7 +285276,7 @@ ${dirty}`
|
|
|
284921
285276
|
|
|
284922
285277
|
// src/mcp/checkSuite.ts
|
|
284923
285278
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync11 } from "node:fs";
|
|
284924
|
-
import { join as
|
|
285279
|
+
import { join as join37 } from "node:path";
|
|
284925
285280
|
import { stripVTControlCharacters } from "node:util";
|
|
284926
285281
|
var GetCheckSuiteLogs = type({
|
|
284927
285282
|
check_suite_id: type.number.describe("the id from check_suite.id")
|
|
@@ -285016,7 +285371,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
285016
285371
|
};
|
|
285017
285372
|
}
|
|
285018
285373
|
const tempDir = getTempDir();
|
|
285019
|
-
const logsDir =
|
|
285374
|
+
const logsDir = join37(tempDir, "ci-logs");
|
|
285020
285375
|
mkdirSync3(logsDir, { recursive: true });
|
|
285021
285376
|
const jobLists = await mapWithConcurrency(
|
|
285022
285377
|
failedRuns,
|
|
@@ -285040,7 +285395,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
285040
285395
|
request: { signal: AbortSignal.timeout(1e4) }
|
|
285041
285396
|
});
|
|
285042
285397
|
const logsText = typeof data === "string" ? data : Buffer.from(data).toString("utf8");
|
|
285043
|
-
const logPath =
|
|
285398
|
+
const logPath = join37(logsDir, `job-${job.id}.log`);
|
|
285044
285399
|
writeFileSync11(logPath, logsText);
|
|
285045
285400
|
const analysis = analyzeLog(logsText, 80);
|
|
285046
285401
|
const failedSteps = job.steps?.filter((s) => s.conclusion === "failure").map((s) => `Step ${s.number}: ${s.name}`) ?? [];
|
|
@@ -285102,7 +285457,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
285102
285457
|
|
|
285103
285458
|
// src/mcp/commitInfo.ts
|
|
285104
285459
|
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
285105
|
-
import { join as
|
|
285460
|
+
import { join as join38 } from "node:path";
|
|
285106
285461
|
var CommitInfo = type({
|
|
285107
285462
|
sha: type.string.describe("the commit SHA (full or abbreviated) to fetch")
|
|
285108
285463
|
});
|
|
@@ -285121,7 +285476,7 @@ function CommitInfoTool(ctx) {
|
|
|
285121
285476
|
const files = data.files ?? [];
|
|
285122
285477
|
const formatResult = formatFilesWithLineNumbers(files);
|
|
285123
285478
|
const tempDir = getTempDir("get_commit_info");
|
|
285124
|
-
const diffFile =
|
|
285479
|
+
const diffFile = join38(tempDir, `commit-${sha.slice(0, 7)}.diff`);
|
|
285125
285480
|
writeFileSync12(diffFile, formatResult.content);
|
|
285126
285481
|
log2.debug(`wrote commit diff to ${diffFile} (${formatResult.content.length} bytes)`);
|
|
285127
285482
|
return {
|
|
@@ -285283,7 +285638,7 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
285283
285638
|
|
|
285284
285639
|
// src/prep/installNodeDependencies.ts
|
|
285285
285640
|
import { existsSync as existsSync8 } from "node:fs";
|
|
285286
|
-
import { join as
|
|
285641
|
+
import { join as join39 } from "node:path";
|
|
285287
285642
|
|
|
285288
285643
|
// node_modules/.pnpm/package-manager-detector@1.8.0/node_modules/package-manager-detector/dist/commands.mjs
|
|
285289
285644
|
function splitRunArgs(args2, valueFlags = []) {
|
|
@@ -285669,7 +286024,7 @@ async function installFallback(name, installSpec) {
|
|
|
285669
286024
|
return result.stderr || `failed to install ${name}`;
|
|
285670
286025
|
}
|
|
285671
286026
|
if (name === "deno") {
|
|
285672
|
-
const denoPath =
|
|
286027
|
+
const denoPath = join39(process.env.HOME || "", ".deno", "bin");
|
|
285673
286028
|
process.env.PATH = `${denoPath}:${process.env.PATH}`;
|
|
285674
286029
|
}
|
|
285675
286030
|
log2.info(`\xBB installed ${name}`);
|
|
@@ -285678,7 +286033,7 @@ async function installFallback(name, installSpec) {
|
|
|
285678
286033
|
var installNodeDependencies = {
|
|
285679
286034
|
name: "installNodeDependencies",
|
|
285680
286035
|
shouldRun: () => {
|
|
285681
|
-
const packageJsonPath =
|
|
286036
|
+
const packageJsonPath = join39(process.cwd(), "package.json");
|
|
285682
286037
|
return existsSync8(packageJsonPath);
|
|
285683
286038
|
},
|
|
285684
286039
|
run: async (options) => {
|
|
@@ -285787,8 +286142,8 @@ ${errorMessage2}`]
|
|
|
285787
286142
|
};
|
|
285788
286143
|
|
|
285789
286144
|
// src/prep/installPythonDependencies.ts
|
|
285790
|
-
import { existsSync as existsSync9, readFileSync as
|
|
285791
|
-
import { join as
|
|
286145
|
+
import { existsSync as existsSync9, readFileSync as readFileSync21 } from "node:fs";
|
|
286146
|
+
import { join as join40 } from "node:path";
|
|
285792
286147
|
var PYTHON_CONFIGS = [
|
|
285793
286148
|
{
|
|
285794
286149
|
file: "requirements.txt",
|
|
@@ -285823,7 +286178,7 @@ var PYTHON_CONFIGS = [
|
|
|
285823
286178
|
];
|
|
285824
286179
|
function pyprojectDeclaresBuildSystem(cwd) {
|
|
285825
286180
|
try {
|
|
285826
|
-
const content =
|
|
286181
|
+
const content = readFileSync21(join40(cwd, "pyproject.toml"), "utf8");
|
|
285827
286182
|
return /^\s*\[build-system\]/m.test(content);
|
|
285828
286183
|
} catch {
|
|
285829
286184
|
return false;
|
|
@@ -285873,13 +286228,13 @@ var installPythonDependencies = {
|
|
|
285873
286228
|
}
|
|
285874
286229
|
const cwd = process.cwd();
|
|
285875
286230
|
return PYTHON_CONFIGS.some(
|
|
285876
|
-
(config3) => existsSync9(
|
|
286231
|
+
(config3) => existsSync9(join40(cwd, config3.file)) && configApplies(config3, cwd)
|
|
285877
286232
|
);
|
|
285878
286233
|
},
|
|
285879
286234
|
run: async (options) => {
|
|
285880
286235
|
const cwd = process.cwd();
|
|
285881
286236
|
const config3 = PYTHON_CONFIGS.find(
|
|
285882
|
-
(c) => existsSync9(
|
|
286237
|
+
(c) => existsSync9(join40(cwd, c.file)) && configApplies(c, cwd)
|
|
285883
286238
|
);
|
|
285884
286239
|
if (!config3) {
|
|
285885
286240
|
return {
|
|
@@ -286400,12 +286755,12 @@ function AddLabelsTool(ctx) {
|
|
|
286400
286755
|
}
|
|
286401
286756
|
|
|
286402
286757
|
// src/mcp/moduleExtraction.ts
|
|
286403
|
-
import { readFileSync as
|
|
286404
|
-
import { join as
|
|
286758
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
286759
|
+
import { join as join43, posix as posix11 } from "node:path";
|
|
286405
286760
|
|
|
286406
286761
|
// src/mcp/terraform/partialInterface.ts
|
|
286407
|
-
import { readdirSync as readdirSync6, readFileSync as
|
|
286408
|
-
import { join as
|
|
286762
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync22 } from "node:fs";
|
|
286763
|
+
import { join as join41 } from "node:path";
|
|
286409
286764
|
function unmappedArguments(resource, moduleResources) {
|
|
286410
286765
|
const matching = moduleResources.filter((m) => m.type === resource.type);
|
|
286411
286766
|
if (matching.length === 0) return [];
|
|
@@ -286415,10 +286770,10 @@ function unmappedArguments(resource, moduleResources) {
|
|
|
286415
286770
|
function readDirHcl(cwd, dir) {
|
|
286416
286771
|
let text = "";
|
|
286417
286772
|
try {
|
|
286418
|
-
for (const f of readdirSync6(
|
|
286773
|
+
for (const f of readdirSync6(join41(cwd, dir)).sort((a, b) => a.localeCompare(b, "en"))) {
|
|
286419
286774
|
if (!f.endsWith(".tf")) continue;
|
|
286420
286775
|
try {
|
|
286421
|
-
text += `${
|
|
286776
|
+
text += `${readFileSync22(join41(cwd, dir, f), "utf8")}
|
|
286422
286777
|
`;
|
|
286423
286778
|
} catch {
|
|
286424
286779
|
}
|
|
@@ -286448,7 +286803,7 @@ function findPartialInterfaces(cwd) {
|
|
|
286448
286803
|
if (isInHouseModule(file2, graph)) continue;
|
|
286449
286804
|
let text;
|
|
286450
286805
|
try {
|
|
286451
|
-
text =
|
|
286806
|
+
text = readFileSync22(join41(cwd, file2), "utf8");
|
|
286452
286807
|
} catch {
|
|
286453
286808
|
continue;
|
|
286454
286809
|
}
|
|
@@ -286465,12 +286820,47 @@ function findPartialInterfaces(cwd) {
|
|
|
286465
286820
|
}
|
|
286466
286821
|
|
|
286467
286822
|
// src/mcp/terraform/refactorScope.ts
|
|
286468
|
-
import {
|
|
286469
|
-
import { join as
|
|
286823
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync23, statSync as statSync6 } from "node:fs";
|
|
286824
|
+
import { join as join42 } from "node:path";
|
|
286470
286825
|
function isExamplePath(path15) {
|
|
286471
|
-
return /(?:^|\/)examples
|
|
286826
|
+
return /(?:^|\/)examples\/|^example\//i.test(path15.replace(/\\/g, "/"));
|
|
286827
|
+
}
|
|
286828
|
+
var PROVIDER_OR_BACKEND = new RegExp(
|
|
286829
|
+
String.raw`(?:^|\n)\s*(?:provider|backend)\s+${BLOCK_LABEL}\s*\{`
|
|
286830
|
+
);
|
|
286831
|
+
var CLOUD_BLOCK = /(?:^|\n)\s*cloud\s*\{/;
|
|
286832
|
+
function configuresDeployment(name, text) {
|
|
286833
|
+
if (name.endsWith(".tf.json")) {
|
|
286834
|
+
let doc;
|
|
286835
|
+
try {
|
|
286836
|
+
doc = JSON.parse(text);
|
|
286837
|
+
} catch {
|
|
286838
|
+
return false;
|
|
286839
|
+
}
|
|
286840
|
+
if (typeof doc !== "object" || doc === null) return false;
|
|
286841
|
+
const { provider: provider2, terraform } = doc;
|
|
286842
|
+
if (provider2 !== void 0) return true;
|
|
286843
|
+
return [terraform].flat().some((t) => typeof t === "object" && t !== null && ("backend" in t || "cloud" in t));
|
|
286844
|
+
}
|
|
286845
|
+
if (PROVIDER_OR_BACKEND.test(text)) return true;
|
|
286846
|
+
return parseBlocks(text, ["terraform"]).some((b) => CLOUD_BLOCK.test(b.body));
|
|
286847
|
+
}
|
|
286848
|
+
var isTerraformFile2 = (name) => name.endsWith(".tf") || name.endsWith(".tf.json");
|
|
286849
|
+
function deploysFrom(dir) {
|
|
286850
|
+
let names;
|
|
286851
|
+
try {
|
|
286852
|
+
names = readdirSync7(dir).filter(isTerraformFile2);
|
|
286853
|
+
} catch {
|
|
286854
|
+
return false;
|
|
286855
|
+
}
|
|
286856
|
+
return names.some((name) => {
|
|
286857
|
+
try {
|
|
286858
|
+
return configuresDeployment(name, readFileSync23(join42(dir, name), "utf8"));
|
|
286859
|
+
} catch {
|
|
286860
|
+
return false;
|
|
286861
|
+
}
|
|
286862
|
+
});
|
|
286472
286863
|
}
|
|
286473
|
-
var PROVIDER_OR_BACKEND = /^\s*(?:provider\s+"|backend\s+")/m;
|
|
286474
286864
|
function holdsTerraform(dir, depth) {
|
|
286475
286865
|
let entries;
|
|
286476
286866
|
try {
|
|
@@ -286479,7 +286869,7 @@ function holdsTerraform(dir, depth) {
|
|
|
286479
286869
|
return false;
|
|
286480
286870
|
}
|
|
286481
286871
|
for (const name of entries) {
|
|
286482
|
-
const path15 =
|
|
286872
|
+
const path15 = join42(dir, name);
|
|
286483
286873
|
if (name.endsWith(".tf")) return true;
|
|
286484
286874
|
if (depth > 0 && !name.startsWith(".") && statSync6(path15, { throwIfNoEntry: false })?.isDirectory()) {
|
|
286485
286875
|
if (holdsTerraform(path15, depth - 1)) return true;
|
|
@@ -286488,26 +286878,35 @@ function holdsTerraform(dir, depth) {
|
|
|
286488
286878
|
return false;
|
|
286489
286879
|
}
|
|
286490
286880
|
function libraryRepoReason(cwd) {
|
|
286491
|
-
let
|
|
286881
|
+
let rootEntries;
|
|
286492
286882
|
try {
|
|
286493
|
-
|
|
286883
|
+
rootEntries = readdirSync7(cwd);
|
|
286494
286884
|
} catch {
|
|
286495
286885
|
return null;
|
|
286496
286886
|
}
|
|
286497
|
-
if (
|
|
286498
|
-
|
|
286499
|
-
|
|
286500
|
-
try {
|
|
286501
|
-
text = readFileSync22(join41(cwd, f), "utf8");
|
|
286502
|
-
} catch {
|
|
286503
|
-
continue;
|
|
286504
|
-
}
|
|
286505
|
-
if (PROVIDER_OR_BACKEND.test(text)) return null;
|
|
286506
|
-
}
|
|
286507
|
-
const examples = ["examples", "example"].find((d) => existsSync10(join41(cwd, d)));
|
|
286508
|
-
if (examples === void 0 || !holdsTerraform(join41(cwd, examples), 2)) return null;
|
|
286887
|
+
if (!rootEntries.some(isTerraformFile2) || deploysFrom(cwd)) return null;
|
|
286888
|
+
const examples = rootEntries.find((d) => /^examples?$/i.test(d));
|
|
286889
|
+
if (examples === void 0 || !holdsTerraform(join42(cwd, examples), 2)) return null;
|
|
286509
286890
|
return `the repository root configures no provider and no backend, and ships \`${examples}/\`: it is a module other configurations call, so restructuring it is churn for every caller`;
|
|
286510
286891
|
}
|
|
286892
|
+
function libraryScope(cwd) {
|
|
286893
|
+
const reason = libraryRepoReason(cwd);
|
|
286894
|
+
if (reason === null) return () => null;
|
|
286895
|
+
const deploys = /* @__PURE__ */ new Map();
|
|
286896
|
+
return (file2) => {
|
|
286897
|
+
const dirs = file2.replace(/\\/g, "/").split("/").slice(0, -1);
|
|
286898
|
+
for (let i = dirs.length; i > 0; i--) {
|
|
286899
|
+
const dir = dirs.slice(0, i).join("/");
|
|
286900
|
+
let d = deploys.get(dir);
|
|
286901
|
+
if (d === void 0) {
|
|
286902
|
+
d = deploysFrom(join42(cwd, dir));
|
|
286903
|
+
deploys.set(dir, d);
|
|
286904
|
+
}
|
|
286905
|
+
if (d) return null;
|
|
286906
|
+
}
|
|
286907
|
+
return reason;
|
|
286908
|
+
};
|
|
286909
|
+
}
|
|
286511
286910
|
function reportOnly(reason) {
|
|
286512
286911
|
return reason === null ? {} : { report_only: true, report_only_reason: reason };
|
|
286513
286912
|
}
|
|
@@ -286800,7 +287199,7 @@ function findExtractionCandidates(cwd, rawCatalogue, orgModuleHcl) {
|
|
|
286800
287199
|
if (isInHouseModule(file2, graph) !== null) continue;
|
|
286801
287200
|
let text;
|
|
286802
287201
|
try {
|
|
286803
|
-
text =
|
|
287202
|
+
text = readFileSync24(join43(cwd, file2), "utf8");
|
|
286804
287203
|
} catch {
|
|
286805
287204
|
continue;
|
|
286806
287205
|
}
|
|
@@ -286865,12 +287264,12 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286865
287264
|
parameters: ModuleExtractionCandidatesParams,
|
|
286866
287265
|
execute: execute(async () => {
|
|
286867
287266
|
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
287267
|
+
const library = libraryScope(cwd);
|
|
286868
287268
|
const candidates = findExtractionCandidates(
|
|
286869
287269
|
cwd,
|
|
286870
287270
|
ctx.payload.moduleCatalogue,
|
|
286871
287271
|
ctx.toolState.orgModuleHcl
|
|
286872
|
-
).filter((c) => ctx.payload.refactorExamples || !isExamplePath(c.cluster.file));
|
|
286873
|
-
const library = libraryRepoReason(cwd);
|
|
287272
|
+
).filter((c) => ctx.payload.refactorExamples || !isExamplePath(c.cluster.file)).map((c) => ({ ...reportOnly(library(c.cluster.file)), ...c }));
|
|
286874
287273
|
const matched = candidates.filter((c) => c.candidates.length > 0);
|
|
286875
287274
|
const reasons = {};
|
|
286876
287275
|
for (const c of candidates)
|
|
@@ -286884,7 +287283,6 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286884
287283
|
`\xBB module_extraction_candidates: ${candidates.length} cluster(s), ${matched.length} with a module match` + (partialInterfaces.length > 0 ? `, ${partialInterfaces.length} partial-interface block(s)` : "")
|
|
286885
287284
|
);
|
|
286886
287285
|
return toolOk({
|
|
286887
|
-
...reportOnly(library),
|
|
286888
287286
|
cluster_count: candidates.length,
|
|
286889
287287
|
matched_count: matched.length,
|
|
286890
287288
|
candidates,
|
|
@@ -286908,8 +287306,8 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286908
287306
|
}
|
|
286909
287307
|
|
|
286910
287308
|
// src/mcp/moduleTests.ts
|
|
286911
|
-
import { existsSync as
|
|
286912
|
-
import { join as
|
|
287309
|
+
import { existsSync as existsSync10, readdirSync as readdirSync8, readFileSync as readFileSync25, statSync as statSync7 } from "node:fs";
|
|
287310
|
+
import { join as join44 } from "node:path";
|
|
286913
287311
|
var MODULE_META_ARGS = /* @__PURE__ */ new Set([
|
|
286914
287312
|
"source",
|
|
286915
287313
|
"version",
|
|
@@ -287029,7 +287427,7 @@ function resolveSourceDir(fromDir, source) {
|
|
|
287029
287427
|
}
|
|
287030
287428
|
function isDir(p) {
|
|
287031
287429
|
try {
|
|
287032
|
-
return
|
|
287430
|
+
return existsSync10(p) && statSync7(p).isDirectory();
|
|
287033
287431
|
} catch {
|
|
287034
287432
|
return false;
|
|
287035
287433
|
}
|
|
@@ -287050,9 +287448,9 @@ function listSubdirs(absDir) {
|
|
|
287050
287448
|
}
|
|
287051
287449
|
function readAllTf(cwd, relDir) {
|
|
287052
287450
|
let text = "";
|
|
287053
|
-
for (const f of listFiles(
|
|
287451
|
+
for (const f of listFiles(join44(cwd, relDir), ".tf")) {
|
|
287054
287452
|
try {
|
|
287055
|
-
text += `${
|
|
287453
|
+
text += `${readFileSync25(join44(cwd, relDir, f), "utf8")}
|
|
287056
287454
|
`;
|
|
287057
287455
|
} catch {
|
|
287058
287456
|
}
|
|
@@ -287064,8 +287462,8 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
287064
287462
|
const assets = [];
|
|
287065
287463
|
const matchesModule = (source, fromDir) => resolveSourceDir(fromDir, source) === md;
|
|
287066
287464
|
for (const examplesRoot of [`${md}/examples`, "examples"]) {
|
|
287067
|
-
if (!isDir(
|
|
287068
|
-
for (const sub of listSubdirs(
|
|
287465
|
+
if (!isDir(join44(cwd, examplesRoot))) continue;
|
|
287466
|
+
for (const sub of listSubdirs(join44(cwd, examplesRoot))) {
|
|
287069
287467
|
const exDir = `${examplesRoot}/${sub}`;
|
|
287070
287468
|
const hcl2 = readAllTf(cwd, exDir);
|
|
287071
287469
|
if (!hcl2) continue;
|
|
@@ -287081,12 +287479,12 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
287081
287479
|
}
|
|
287082
287480
|
}
|
|
287083
287481
|
for (const testDir of [`${md}/tests`, md]) {
|
|
287084
|
-
if (!isDir(
|
|
287085
|
-
for (const f of listFiles(
|
|
287482
|
+
if (!isDir(join44(cwd, testDir))) continue;
|
|
287483
|
+
for (const f of listFiles(join44(cwd, testDir), ".tftest.hcl")) {
|
|
287086
287484
|
const rel = `${testDir}/${f}`;
|
|
287087
287485
|
let hcl2;
|
|
287088
287486
|
try {
|
|
287089
|
-
hcl2 =
|
|
287487
|
+
hcl2 = readFileSync25(join44(cwd, rel), "utf8");
|
|
287090
287488
|
} catch {
|
|
287091
287489
|
continue;
|
|
287092
287490
|
}
|
|
@@ -287094,12 +287492,12 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
287094
287492
|
}
|
|
287095
287493
|
}
|
|
287096
287494
|
for (const goDir of [`${md}/test`, `${md}/tests`]) {
|
|
287097
|
-
if (!isDir(
|
|
287098
|
-
for (const f of listFiles(
|
|
287495
|
+
if (!isDir(join44(cwd, goDir))) continue;
|
|
287496
|
+
for (const f of listFiles(join44(cwd, goDir), "_test.go")) {
|
|
287099
287497
|
const rel = `${goDir}/${f}`;
|
|
287100
287498
|
let go;
|
|
287101
287499
|
try {
|
|
287102
|
-
go =
|
|
287500
|
+
go = readFileSync25(join44(cwd, rel), "utf8");
|
|
287103
287501
|
} catch {
|
|
287104
287502
|
continue;
|
|
287105
287503
|
}
|
|
@@ -287223,8 +287621,8 @@ function SetOutputTool(ctx, outputSchema) {
|
|
|
287223
287621
|
|
|
287224
287622
|
// src/mcp/policy.ts
|
|
287225
287623
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
287226
|
-
import { existsSync as
|
|
287227
|
-
import { join as
|
|
287624
|
+
import { existsSync as existsSync11, readFileSync as readFileSync26 } from "node:fs";
|
|
287625
|
+
import { join as join45 } from "node:path";
|
|
287228
287626
|
function parseConftestOutput(stdout) {
|
|
287229
287627
|
let parsed2;
|
|
287230
287628
|
try {
|
|
@@ -287258,7 +287656,7 @@ var CONFTEST_CONFIG = "conftest.toml";
|
|
|
287258
287656
|
function conftestSelectsNamespaces(conftestCwd) {
|
|
287259
287657
|
let raw2;
|
|
287260
287658
|
try {
|
|
287261
|
-
raw2 =
|
|
287659
|
+
raw2 = readFileSync26(join45(conftestCwd, CONFTEST_CONFIG), "utf-8");
|
|
287262
287660
|
} catch {
|
|
287263
287661
|
return false;
|
|
287264
287662
|
}
|
|
@@ -287274,8 +287672,8 @@ function namespaceArgs(conftestCwd) {
|
|
|
287274
287672
|
}
|
|
287275
287673
|
function findPlanJson(cwd) {
|
|
287276
287674
|
for (const candidate of PLAN_JSON_NAMES) {
|
|
287277
|
-
const abs =
|
|
287278
|
-
if (
|
|
287675
|
+
const abs = join45(cwd, candidate);
|
|
287676
|
+
if (existsSync11(abs)) return abs;
|
|
287279
287677
|
}
|
|
287280
287678
|
return null;
|
|
287281
287679
|
}
|
|
@@ -287316,11 +287714,11 @@ function resolvePolicyDir(cwd, explicit) {
|
|
|
287316
287714
|
} catch {
|
|
287317
287715
|
return null;
|
|
287318
287716
|
}
|
|
287319
|
-
return
|
|
287717
|
+
return existsSync11(abs) ? abs : null;
|
|
287320
287718
|
}
|
|
287321
287719
|
for (const d of DEFAULT_POLICY_DIRS) {
|
|
287322
|
-
const abs =
|
|
287323
|
-
if (
|
|
287720
|
+
const abs = join45(cwd, d);
|
|
287721
|
+
if (existsSync11(abs)) return abs;
|
|
287324
287722
|
}
|
|
287325
287723
|
return null;
|
|
287326
287724
|
}
|
|
@@ -287354,7 +287752,7 @@ function PolicyCheckTool(ctx) {
|
|
|
287354
287752
|
} catch {
|
|
287355
287753
|
abs = null;
|
|
287356
287754
|
}
|
|
287357
|
-
targetFile = abs &&
|
|
287755
|
+
targetFile = abs && existsSync11(abs) ? abs : null;
|
|
287358
287756
|
if (!targetFile) {
|
|
287359
287757
|
return toolSkip(
|
|
287360
287758
|
"target_not_found",
|
|
@@ -287627,9 +288025,9 @@ function PullRequestInfoTool(ctx) {
|
|
|
287627
288025
|
|
|
287628
288026
|
// node_modules/.pnpm/@infraweaver-io+sandbox@0.1.8/node_modules/@infraweaver-io/sandbox/dist/writePolicy.js
|
|
287629
288027
|
import { renameSync, writeFileSync as writeFileSync13 } from "node:fs";
|
|
287630
|
-
import { join as
|
|
288028
|
+
import { join as join46 } from "node:path";
|
|
287631
288029
|
function writePolicyPath(tmpdir5, filename) {
|
|
287632
|
-
return
|
|
288030
|
+
return join46(tmpdir5, filename);
|
|
287633
288031
|
}
|
|
287634
288032
|
function publishWritePolicy(params) {
|
|
287635
288033
|
try {
|
|
@@ -287800,12 +288198,12 @@ function SelectModeTool(ctx) {
|
|
|
287800
288198
|
}
|
|
287801
288199
|
|
|
287802
288200
|
// src/mcp/terraform/tools/advise.ts
|
|
287803
|
-
import { existsSync as
|
|
287804
|
-
import { join as
|
|
288201
|
+
import { existsSync as existsSync12, readFileSync as readFileSync28 } from "node:fs";
|
|
288202
|
+
import { join as join48 } from "node:path";
|
|
287805
288203
|
|
|
287806
288204
|
// src/mcp/terraform/fixMemory.ts
|
|
287807
|
-
import { readFileSync as
|
|
287808
|
-
import { join as
|
|
288205
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
288206
|
+
import { join as join47 } from "node:path";
|
|
287809
288207
|
var FIX_MEMORY_FILENAME = FIX_MEMORY_FILE;
|
|
287810
288208
|
var MAX_DESCRIPTION = 400;
|
|
287811
288209
|
var MAX_BEFORE_EXAMPLE = 1200;
|
|
@@ -287892,7 +288290,7 @@ function loadFixMemory(cwd) {
|
|
|
287892
288290
|
const root = cwd ?? process.cwd();
|
|
287893
288291
|
for (const filename of [FIX_MEMORY_FILENAME, LEGACY_FIX_MEMORY_FILENAME]) {
|
|
287894
288292
|
try {
|
|
287895
|
-
return parseFixMemory(
|
|
288293
|
+
return parseFixMemory(readFileSync27(join47(root, filename), "utf-8")) ?? [];
|
|
287896
288294
|
} catch {
|
|
287897
288295
|
}
|
|
287898
288296
|
}
|
|
@@ -287958,10 +288356,10 @@ function inlineWaivers(content, file2) {
|
|
|
287958
288356
|
];
|
|
287959
288357
|
}
|
|
287960
288358
|
function readLearnings(tmpdir5) {
|
|
287961
|
-
const path15 =
|
|
287962
|
-
if (!
|
|
288359
|
+
const path15 = join48(tmpdir5, LEARNINGS_FILE);
|
|
288360
|
+
if (!existsSync12(path15)) return [];
|
|
287963
288361
|
try {
|
|
287964
|
-
return
|
|
288362
|
+
return readFileSync28(path15, "utf-8").split("\n");
|
|
287965
288363
|
} catch {
|
|
287966
288364
|
return [];
|
|
287967
288365
|
}
|
|
@@ -287980,7 +288378,7 @@ function runAdvise(ctx, input2) {
|
|
|
287980
288378
|
const learnings = readLearnings(ctx.tmpdir);
|
|
287981
288379
|
const openConcerns = session.lastScanConcerns;
|
|
287982
288380
|
const dossiers = files.map((file2) => {
|
|
287983
|
-
const content = readTextCapped(
|
|
288381
|
+
const content = readTextCapped(join48(cwd, file2));
|
|
287984
288382
|
const inline = content === null ? [] : inlineWaivers(content, file2);
|
|
287985
288383
|
const reviewedInline = reviewedCopy(
|
|
287986
288384
|
cwd,
|
|
@@ -289318,8 +289716,8 @@ function ConsolidationCandidatesTool(ctx) {
|
|
|
289318
289716
|
}
|
|
289319
289717
|
|
|
289320
289718
|
// src/mcp/terraform/tools/detectPlanDrift.ts
|
|
289321
|
-
import { readFileSync as
|
|
289322
|
-
import { join as
|
|
289719
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
289720
|
+
import { join as join49 } from "node:path";
|
|
289323
289721
|
|
|
289324
289722
|
// src/mcp/terraform/cspm.ts
|
|
289325
289723
|
var ExternalResource = type({
|
|
@@ -289737,7 +290135,7 @@ function readTfFiles(cwd) {
|
|
|
289737
290135
|
const out = [];
|
|
289738
290136
|
for (const file2 of walkTfFiles(cwd)) {
|
|
289739
290137
|
try {
|
|
289740
|
-
out.push({ file: file2, hcl:
|
|
290138
|
+
out.push({ file: file2, hcl: readFileSync29(join49(cwd, file2), "utf8") });
|
|
289741
290139
|
} catch {
|
|
289742
290140
|
}
|
|
289743
290141
|
}
|
|
@@ -289754,7 +290152,7 @@ function DetectPlanDriftTool(ctx) {
|
|
|
289754
290152
|
const planPath = path15 || !envPlanPath ? resolveWithinCwd(cwd, path15 ?? "plan.json") : envPlanPath;
|
|
289755
290153
|
let raw2;
|
|
289756
290154
|
try {
|
|
289757
|
-
raw2 =
|
|
290155
|
+
raw2 = readFileSync29(planPath, "utf8");
|
|
289758
290156
|
} catch {
|
|
289759
290157
|
return skipResult(
|
|
289760
290158
|
"plan_artifact_not_found",
|
|
@@ -289824,7 +290222,8 @@ function DetectPlanDriftTool(ctx) {
|
|
|
289824
290222
|
autonomyThreshold,
|
|
289825
290223
|
// drift is a narrow concern source — join any prior scan baseline so a
|
|
289826
290224
|
// later ✗→✓ verify doesn't read the whole workspace as regressions.
|
|
289827
|
-
baselineMode: "merge"
|
|
290225
|
+
baselineMode: "merge",
|
|
290226
|
+
openRemediationPrs: await listOpenRemediationPrs(ctx)
|
|
289828
290227
|
});
|
|
289829
290228
|
log2.info(
|
|
289830
290229
|
`\xBB detect_plan_drift: ${active.length} drifted resource(s) \u2265 ${threshold} from ${planPath}` + (noiseFiltered.length ? `, ${noiseFiltered.length} noise-filtered` : "") + (unlocated.length ? `, ${unlocated.length} unlocated` : "") + (statefulForgotten.length ? `, ${statefulForgotten.length} STATEFUL forget(s)` : "") + (suppressed.length ? ` (${suppressed.length} suppressed)` : "")
|
|
@@ -289886,13 +290285,13 @@ function DetectPlanDriftTool(ctx) {
|
|
|
289886
290285
|
}
|
|
289887
290286
|
|
|
289888
290287
|
// src/mcp/terraform/tools/emitCost.ts
|
|
289889
|
-
import { readFileSync as
|
|
289890
|
-
import { join as
|
|
290288
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync14 } from "node:fs";
|
|
290289
|
+
import { join as join50 } from "node:path";
|
|
289891
290290
|
|
|
289892
290291
|
// src/mcp/terraform/awsPrices.ts
|
|
289893
290292
|
var AWS_PRICE_REGION = "eu-west-2";
|
|
289894
290293
|
var AWS_PRICE_CURRENCY = "USD";
|
|
289895
|
-
var AWS_PRICE_FETCHED_AT = "2026-
|
|
290294
|
+
var AWS_PRICE_FETCHED_AT = "2026-10-03";
|
|
289896
290295
|
var AWS_HOURLY_PRICES = {
|
|
289897
290296
|
"eks-cluster-standard": 0.1,
|
|
289898
290297
|
"elb-application": 0.02646,
|
|
@@ -289910,30 +290309,30 @@ var AWS_PER_GB_PRICES = {
|
|
|
289910
290309
|
// src/mcp/terraform/azurePrices.ts
|
|
289911
290310
|
var AZURE_PRICE_REGION = "westeurope";
|
|
289912
290311
|
var AZURE_PRICE_CURRENCY = "EUR";
|
|
289913
|
-
var AZURE_PRICE_FETCHED_AT = "2026-
|
|
290312
|
+
var AZURE_PRICE_FETCHED_AT = "2026-10-03";
|
|
289914
290313
|
var AZURE_HOURLY_PRICES = {
|
|
289915
|
-
"app-service-p0v3": 0.
|
|
289916
|
-
"app-service-p1v3": 0.
|
|
289917
|
-
"app-service-p2v3": 0.
|
|
289918
|
-
"app-service-p3v3": 0.
|
|
289919
|
-
"bastion-basic": 0.
|
|
289920
|
-
"bastion-premium": 0.
|
|
289921
|
-
"bastion-standard": 0.
|
|
289922
|
-
"firewall-basic": 0.
|
|
289923
|
-
"firewall-premium": 1.
|
|
289924
|
-
"firewall-standard": 1.
|
|
289925
|
-
"redis-c0": 0.
|
|
289926
|
-
"redis-c1": 0.
|
|
289927
|
-
"redis-c2": 0.
|
|
289928
|
-
"redis-c3": 0.
|
|
289929
|
-
"redis-p1": 0.
|
|
289930
|
-
"redis-p2": 0.
|
|
289931
|
-
"redis-p3": 0.
|
|
289932
|
-
"vpn-gateway-vpngw1": 0.
|
|
289933
|
-
"vpn-gateway-vpngw2": 0.
|
|
289934
|
-
"vpn-gateway-vpngw3": 1.
|
|
289935
|
-
"vpn-gateway-vpngw4": 1.
|
|
289936
|
-
"vpn-gateway-vpngw5": 3.
|
|
290314
|
+
"app-service-p0v3": 0.0783,
|
|
290315
|
+
"app-service-p1v3": 0.1566,
|
|
290316
|
+
"app-service-p2v3": 0.3133,
|
|
290317
|
+
"app-service-p3v3": 0.6265,
|
|
290318
|
+
"bastion-basic": 0.1672,
|
|
290319
|
+
"bastion-premium": 0.396,
|
|
290320
|
+
"bastion-standard": 0.2552,
|
|
290321
|
+
"firewall-basic": 0.3476,
|
|
290322
|
+
"firewall-premium": 1.54,
|
|
290323
|
+
"firewall-standard": 1.1,
|
|
290324
|
+
"redis-c0": 0.0242,
|
|
290325
|
+
"redis-c1": 0.0607,
|
|
290326
|
+
"redis-c2": 0.0986,
|
|
290327
|
+
"redis-c3": 0.198,
|
|
290328
|
+
"redis-p1": 0.2438,
|
|
290329
|
+
"redis-p2": 0.4884,
|
|
290330
|
+
"redis-p3": 0.9759,
|
|
290331
|
+
"vpn-gateway-vpngw1": 0.1672,
|
|
290332
|
+
"vpn-gateway-vpngw2": 0.4312,
|
|
290333
|
+
"vpn-gateway-vpngw3": 1.1,
|
|
290334
|
+
"vpn-gateway-vpngw4": 1.8479,
|
|
290335
|
+
"vpn-gateway-vpngw5": 3.2119
|
|
289937
290336
|
};
|
|
289938
290337
|
|
|
289939
290338
|
// src/mcp/terraform/idleFloor.ts
|
|
@@ -290211,7 +290610,7 @@ function readTfFiles2(cwd) {
|
|
|
290211
290610
|
const out = [];
|
|
290212
290611
|
for (const file2 of walkTfFiles(cwd)) {
|
|
290213
290612
|
try {
|
|
290214
|
-
out.push({ file: file2, hcl:
|
|
290613
|
+
out.push({ file: file2, hcl: readFileSync30(join50(cwd, file2), "utf8") });
|
|
290215
290614
|
} catch {
|
|
290216
290615
|
}
|
|
290217
290616
|
}
|
|
@@ -290316,7 +290715,7 @@ function buildSuppressionSummary(waivers) {
|
|
|
290316
290715
|
}
|
|
290317
290716
|
|
|
290318
290717
|
// node_modules/.pnpm/@infraweaver-io+attest@0.1.7_supports-color@7.2.0/node_modules/@infraweaver-io/attest/dist/signing.js
|
|
290319
|
-
import { createHash as
|
|
290718
|
+
import { createHash as createHash11, createPrivateKey, createPublicKey, sign as cryptoSign, verify as cryptoVerify } from "node:crypto";
|
|
290320
290719
|
var SIGNATURE_ALGORITHM = "Ed25519";
|
|
290321
290720
|
var DEFAULT_KEY_LABEL = "the signing key";
|
|
290322
290721
|
function loadSigningKey(raw2, options) {
|
|
@@ -290343,7 +290742,7 @@ function loadSigningKey(raw2, options) {
|
|
|
290343
290742
|
return {
|
|
290344
290743
|
privateKey,
|
|
290345
290744
|
publicKeyPem,
|
|
290346
|
-
fingerprint:
|
|
290745
|
+
fingerprint: createHash11("sha256").update(spkiDer).digest("hex")
|
|
290347
290746
|
};
|
|
290348
290747
|
}
|
|
290349
290748
|
function signBytes(bytes, key) {
|
|
@@ -290578,7 +290977,7 @@ function buildEvidenceBundle(args2) {
|
|
|
290578
290977
|
// node_modules/.pnpm/@infraweaver-io+attest@0.1.7_supports-color@7.2.0/node_modules/@infraweaver-io/attest/dist/keyless.js
|
|
290579
290978
|
var import_bundle = __toESM(require_dist6(), 1);
|
|
290580
290979
|
var import_sign = __toESM(require_dist9(), 1);
|
|
290581
|
-
import { createHash as
|
|
290980
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
290582
290981
|
|
|
290583
290982
|
// node_modules/.pnpm/@infraweaver-io+attest@0.1.7_supports-color@7.2.0/node_modules/@infraweaver-io/attest/dist/keylessOidc.js
|
|
290584
290983
|
var SIGSTORE_OIDC_AUDIENCE = "sigstore";
|
|
@@ -290607,7 +291006,7 @@ function keylessSigningPossible(env2, envName) {
|
|
|
290607
291006
|
}
|
|
290608
291007
|
function buildInTotoStatement(args2) {
|
|
290609
291008
|
const data = typeof args2.artifactBytes === "string" ? Buffer.from(args2.artifactBytes, "utf8") : args2.artifactBytes;
|
|
290610
|
-
const sha2562 =
|
|
291009
|
+
const sha2562 = createHash12("sha256").update(data).digest("hex");
|
|
290611
291010
|
return {
|
|
290612
291011
|
_type: "https://in-toto.io/Statement/v1",
|
|
290613
291012
|
subject: [{ name: args2.subjectName, digest: { sha256: sha2562 } }],
|
|
@@ -290817,12 +291216,12 @@ import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
|
290817
291216
|
import { dirname as dirname6 } from "node:path";
|
|
290818
291217
|
|
|
290819
291218
|
// src/mcp/terraform/oscal.ts
|
|
290820
|
-
import { createHash as
|
|
291219
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
290821
291220
|
var OSCAL_VERSION = "1.1.2";
|
|
290822
291221
|
var INDICATIVE_REMARK = "Indicative, crosswalk-derived assessment from a deterministic starter rule-pack \u2014 NOT a formal OSCAL assessment against an authored assessment plan. Statuses are code-verified only; absence of a finding is not proof of compliance.";
|
|
290823
291222
|
var NS = "https://infraweaver.io/ns/oscal";
|
|
290824
291223
|
function deterministicUuid(seed) {
|
|
290825
|
-
const hex4 =
|
|
291224
|
+
const hex4 = createHash13("sha256").update(seed).digest("hex").slice(0, 32).split("");
|
|
290826
291225
|
hex4[12] = "5";
|
|
290827
291226
|
hex4[16] = (Number.parseInt(hex4[16] ?? "0", 16) & 3 | 8).toString(16);
|
|
290828
291227
|
const u = hex4.join("");
|
|
@@ -291475,7 +291874,7 @@ function TerraformEmitVexTool(ctx) {
|
|
|
291475
291874
|
// src/mcp/terraform/tools/equivalenceCheck.ts
|
|
291476
291875
|
import { mkdtempSync as mkdtempSync5, rmSync as rmSync7 } from "node:fs";
|
|
291477
291876
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
291478
|
-
import { join as
|
|
291877
|
+
import { join as join51 } from "node:path";
|
|
291479
291878
|
|
|
291480
291879
|
// src/mcp/terraform/refactor/attribution.ts
|
|
291481
291880
|
import { posix as posix13 } from "node:path";
|
|
@@ -291938,16 +292337,32 @@ function uncoveredInstanceKeys(p) {
|
|
|
291938
292337
|
if (expected === null) return null;
|
|
291939
292338
|
const kind = level[0].kind;
|
|
291940
292339
|
const written = (k) => kind === "count" ? k : `"${k}"`;
|
|
292340
|
+
const fromAt = level[0].at;
|
|
292341
|
+
const toAt = p.after.multiplicity[0]?.at;
|
|
292342
|
+
if (fromAt === void 0 || toAt === void 0) return null;
|
|
291941
292343
|
const declared2 = /* @__PURE__ */ new Set();
|
|
291942
292344
|
for (const blk of p.blocks) {
|
|
292345
|
+
if (stripIndices(normaliseAddress(blk.from)) !== p.before.address || stripIndices(normaliseAddress(blk.to)) !== p.after.address)
|
|
292346
|
+
return null;
|
|
291943
292347
|
const from = instanceKeysOf(blk.from);
|
|
291944
292348
|
const to = instanceKeysOf(blk.to);
|
|
291945
292349
|
if (from.length > 1 || to.length > 1) return null;
|
|
291946
292350
|
if (from.length === 0 && to.length === 0) return null;
|
|
291947
|
-
if (from.length
|
|
292351
|
+
if (from.length !== 1 || to.length !== 1 || from[0] !== to[0]) continue;
|
|
292352
|
+
const fromPlaced = keyAtLevel(blk.from, fromAt);
|
|
292353
|
+
const toPlaced = keyAtLevel(blk.to, toAt);
|
|
292354
|
+
if (fromPlaced === false || toPlaced === false) continue;
|
|
292355
|
+
if (fromPlaced === null || toPlaced === null) return null;
|
|
292356
|
+
declared2.add(from[0]);
|
|
291948
292357
|
}
|
|
291949
292358
|
return expected.filter((k) => !declared2.has(written(k)));
|
|
291950
292359
|
}
|
|
292360
|
+
function keyAtLevel(address, at) {
|
|
292361
|
+
const onResource = instanceKeysOf(stripModuleHops(normaliseAddress(address))).length > 0;
|
|
292362
|
+
if (at === "resource") return onResource;
|
|
292363
|
+
if (onResource) return false;
|
|
292364
|
+
return moduleHops(address).length === 1 ? true : null;
|
|
292365
|
+
}
|
|
291951
292366
|
function computeEquivalence(before, after, movedBlocks, ambiguous = [], planPairs, opts = {}) {
|
|
291952
292367
|
const reasons = [];
|
|
291953
292368
|
const corr = correspond(before, after, movedBlocks);
|
|
@@ -293267,12 +293682,12 @@ async function baselineValidateErrors(cwd, base, env2, session) {
|
|
|
293267
293682
|
}
|
|
293268
293683
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd);
|
|
293269
293684
|
if (prefix2.status !== 0) return null;
|
|
293270
|
-
const tree = mkdtempSync5(
|
|
293685
|
+
const tree = mkdtempSync5(join51(tmpdir3(), "iw-baseline-"));
|
|
293271
293686
|
try {
|
|
293272
293687
|
if (run("git", ["worktree", "add", "--detach", "--quiet", tree, base], cwd).status !== 0) {
|
|
293273
293688
|
return null;
|
|
293274
293689
|
}
|
|
293275
|
-
const outcome2 = await scanValidate(
|
|
293690
|
+
const outcome2 = await scanValidate(join51(tree, prefix2.stdout.trim()), env2);
|
|
293276
293691
|
if (!outcome2.ran || outcome2.unvalidated) return null;
|
|
293277
293692
|
const errors = outcome2.concerns.map(validateErrorKey);
|
|
293278
293693
|
session.baselineValidateErrors = { base, errors };
|
|
@@ -293373,7 +293788,7 @@ function TerraformGenerateMovedTool(ctx) {
|
|
|
293373
293788
|
|
|
293374
293789
|
// src/mcp/terraform/cost.ts
|
|
293375
293790
|
import { mkdtempSync as mkdtempSync6, rmSync as rmSync8 } from "node:fs";
|
|
293376
|
-
import { join as
|
|
293791
|
+
import { join as join52 } from "node:path";
|
|
293377
293792
|
function parseInfracostBreakdown(stdout) {
|
|
293378
293793
|
const parsed2 = parseScannerJson(InfracostBreakdownOutput, stdout, "infracost");
|
|
293379
293794
|
const raw2 = parsed2.totalMonthlyCost;
|
|
@@ -293455,15 +293870,15 @@ async function infracostBaseline(cwd, key, tmpdir5) {
|
|
|
293455
293870
|
if (!baseRef) return null;
|
|
293456
293871
|
const prefixResult = run("git", ["rev-parse", "--show-prefix"], cwd);
|
|
293457
293872
|
const prefix2 = prefixResult.status === 0 ? prefixResult.stdout.trim() : "";
|
|
293458
|
-
const baseDir = mkdtempSync6(
|
|
293459
|
-
const worktree =
|
|
293873
|
+
const baseDir = mkdtempSync6(join52(tmpdir5, "infracost-base-"));
|
|
293874
|
+
const worktree = join52(baseDir, "wt");
|
|
293460
293875
|
const add = run("git", ["worktree", "add", "--detach", worktree, baseRef], cwd);
|
|
293461
293876
|
if (add.status !== 0) {
|
|
293462
293877
|
rmSync8(baseDir, { recursive: true, force: true });
|
|
293463
293878
|
return null;
|
|
293464
293879
|
}
|
|
293465
293880
|
try {
|
|
293466
|
-
const scanCwd = prefix2 ?
|
|
293881
|
+
const scanCwd = prefix2 ? join52(worktree, prefix2) : worktree;
|
|
293467
293882
|
const r = await runInfracostBreakdown(scanCwd, key);
|
|
293468
293883
|
if (r.missing || r.status !== 0) return null;
|
|
293469
293884
|
return parseInfracostBreakdown(r.stdout);
|
|
@@ -293534,7 +293949,7 @@ function InfracostDiffTool(ctx) {
|
|
|
293534
293949
|
|
|
293535
293950
|
// src/mcp/terraform/tools/ingestExternalFindings.ts
|
|
293536
293951
|
import { statSync as statSync8 } from "node:fs";
|
|
293537
|
-
import { join as
|
|
293952
|
+
import { join as join53 } from "node:path";
|
|
293538
293953
|
|
|
293539
293954
|
// src/mcp/terraform/prowlerOcsf.ts
|
|
293540
293955
|
var DETECTION_FINDING_CREATE = 200401;
|
|
@@ -293760,7 +294175,7 @@ var MAX_FEED_BYTES = 100 * 1024 * 1024;
|
|
|
293760
294175
|
function readTfFiles3(cwd) {
|
|
293761
294176
|
const out = [];
|
|
293762
294177
|
for (const file2 of walkTfFiles(cwd)) {
|
|
293763
|
-
const hcl2 = readTextCapped(
|
|
294178
|
+
const hcl2 = readTextCapped(join53(cwd, file2));
|
|
293764
294179
|
if (hcl2 !== null) out.push({ file: file2, hcl: hcl2 });
|
|
293765
294180
|
}
|
|
293766
294181
|
return out;
|
|
@@ -293874,7 +294289,8 @@ function IngestExternalFindingsTool(ctx) {
|
|
|
293874
294289
|
// an external feed is a narrow concern source — join any prior scan
|
|
293875
294290
|
// baseline so a later ✗→✓ verify doesn't read the workspace as regressions.
|
|
293876
294291
|
baselineMode: "merge",
|
|
293877
|
-
seedCaps: seedCapsFrom(input2)
|
|
294292
|
+
seedCaps: seedCapsFrom(input2),
|
|
294293
|
+
openRemediationPrs: await listOpenRemediationPrs(ctx)
|
|
293878
294294
|
});
|
|
293879
294295
|
const cappedBlock = cappedSummary(capped);
|
|
293880
294296
|
log2.info(
|
|
@@ -293917,8 +294333,8 @@ function IngestExternalFindingsTool(ctx) {
|
|
|
293917
294333
|
}
|
|
293918
294334
|
|
|
293919
294335
|
// src/mcp/terraform/tools/moduleDocs.ts
|
|
293920
|
-
import { readFileSync as
|
|
293921
|
-
import { join as
|
|
294336
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "node:fs";
|
|
294337
|
+
import { join as join54 } from "node:path";
|
|
293922
294338
|
|
|
293923
294339
|
// src/mcp/terraform/moduleDocs.ts
|
|
293924
294340
|
var VERDICT_CLAIM = {
|
|
@@ -294032,7 +294448,7 @@ function TerraformModuleDocsTool(ctx) {
|
|
|
294032
294448
|
);
|
|
294033
294449
|
}
|
|
294034
294450
|
const absDir = resolveWithinCwd(cwd, module_dir);
|
|
294035
|
-
const target =
|
|
294451
|
+
const target = join54(absDir, "README.md");
|
|
294036
294452
|
let gitHead = null;
|
|
294037
294453
|
try {
|
|
294038
294454
|
gitHead = $("git", ["rev-parse", "HEAD"], { cwd, log: false });
|
|
@@ -294040,7 +294456,7 @@ function TerraformModuleDocsTool(ctx) {
|
|
|
294040
294456
|
}
|
|
294041
294457
|
let existing = null;
|
|
294042
294458
|
try {
|
|
294043
|
-
existing =
|
|
294459
|
+
existing = readFileSync31(target, "utf8");
|
|
294044
294460
|
} catch {
|
|
294045
294461
|
}
|
|
294046
294462
|
const priorHead = readFooterGitHead(existing);
|
|
@@ -294344,15 +294760,13 @@ function NormalizationCandidatesTool(ctx) {
|
|
|
294344
294760
|
parameters: NormalizationCandidatesParams,
|
|
294345
294761
|
execute: execute(async () => {
|
|
294346
294762
|
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
294347
|
-
const
|
|
294348
|
-
|
|
294349
|
-
);
|
|
294763
|
+
const library = libraryScope(cwd);
|
|
294764
|
+
const files = findNormalizationCandidates(cwd).filter((f) => ctx.payload.refactorExamples || !isExamplePath(f.file)).map((f) => ({ ...reportOnly(library(f.file)), ...f }));
|
|
294350
294765
|
const total = files.reduce((n, f) => n + f.count, 0);
|
|
294351
294766
|
log2.info(
|
|
294352
294767
|
`\xBB terraform_normalization_candidates: ${total} site(s) across ${files.length} file(s)`
|
|
294353
294768
|
);
|
|
294354
294769
|
return toolOk({
|
|
294355
|
-
...reportOnly(libraryRepoReason(cwd)),
|
|
294356
294770
|
file_count: files.length,
|
|
294357
294771
|
total,
|
|
294358
294772
|
files,
|
|
@@ -294364,7 +294778,7 @@ function NormalizationCandidatesTool(ctx) {
|
|
|
294364
294778
|
|
|
294365
294779
|
// src/mcp/terraform/tools/plan.ts
|
|
294366
294780
|
import { rmSync as rmSync9 } from "node:fs";
|
|
294367
|
-
import { join as
|
|
294781
|
+
import { join as join55 } from "node:path";
|
|
294368
294782
|
var PLAN_JSON_ARGS = ["plan", "-input=false", "-no-color", "-lock=false", "-json"];
|
|
294369
294783
|
var planFileSeq = 0;
|
|
294370
294784
|
async function capturePlanPairs(absDir, planFile, creds) {
|
|
@@ -294387,7 +294801,7 @@ async function planOneRoot(absDir, creds, tmpdir5) {
|
|
|
294387
294801
|
skipReason: `terraform init failed: ${init.stderr.trim().slice(0, 200) || "unknown error"}`
|
|
294388
294802
|
};
|
|
294389
294803
|
}
|
|
294390
|
-
const planFile = tmpdir5 ?
|
|
294804
|
+
const planFile = tmpdir5 ? join55(tmpdir5, `plan-${process.pid}-${planFileSeq++}.tfplan`) : void 0;
|
|
294391
294805
|
const plan = await runTfAsync(
|
|
294392
294806
|
planFile ? [...PLAN_JSON_ARGS, `-out=${planFile}`] : PLAN_JSON_ARGS,
|
|
294393
294807
|
absDir,
|
|
@@ -294757,8 +295171,8 @@ function TerraformProviderUpgradeTool(ctx) {
|
|
|
294757
295171
|
}
|
|
294758
295172
|
|
|
294759
295173
|
// src/mcp/terraform/tfquery.ts
|
|
294760
|
-
import { readFileSync as
|
|
294761
|
-
import { join as
|
|
295174
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
295175
|
+
import { join as join56 } from "node:path";
|
|
294762
295176
|
var TFQUERY_SUFFIX = ".tfquery.hcl";
|
|
294763
295177
|
function parseQueryFile(hcl2) {
|
|
294764
295178
|
return parseBlocks(hcl2, ["list"]).map((block) => {
|
|
@@ -294784,7 +295198,7 @@ function collectQueryInventory(cwd) {
|
|
|
294784
295198
|
for (const rel of walkFilesBySuffix(cwd, TFQUERY_SUFFIX)) {
|
|
294785
295199
|
let text;
|
|
294786
295200
|
try {
|
|
294787
|
-
text =
|
|
295201
|
+
text = readFileSync32(join56(cwd, rel), "utf8");
|
|
294788
295202
|
} catch {
|
|
294789
295203
|
continue;
|
|
294790
295204
|
}
|
|
@@ -294819,7 +295233,7 @@ function TerraformQueryInventoryTool(ctx) {
|
|
|
294819
295233
|
}
|
|
294820
295234
|
|
|
294821
295235
|
// src/mcp/terraform/tools/readFindings.ts
|
|
294822
|
-
import { readFileSync as
|
|
295236
|
+
import { readFileSync as readFileSync33 } from "node:fs";
|
|
294823
295237
|
var ReadFindingsParams = type({
|
|
294824
295238
|
"path?": type.string.describe(
|
|
294825
295239
|
"path to the Assessor's findings.json. Defaults to $INFRAWEAVER_FINDINGS_PATH, then ./findings.json in the workspace."
|
|
@@ -294844,7 +295258,7 @@ function ReadFindingsTool(ctx) {
|
|
|
294844
295258
|
const findingsPath = path15 || !envFindingsPath ? resolveWithinCwd(cwd, path15 ?? "findings.json") : envFindingsPath;
|
|
294845
295259
|
let raw2;
|
|
294846
295260
|
try {
|
|
294847
|
-
raw2 =
|
|
295261
|
+
raw2 = readFileSync33(findingsPath, "utf8");
|
|
294848
295262
|
} catch {
|
|
294849
295263
|
return skipResult(
|
|
294850
295264
|
"findings_not_found",
|
|
@@ -294887,7 +295301,8 @@ function ReadFindingsTool(ctx) {
|
|
|
294887
295301
|
minRank,
|
|
294888
295302
|
grouping,
|
|
294889
295303
|
autonomyThreshold,
|
|
294890
|
-
seedCaps: seedCapsFrom(input2)
|
|
295304
|
+
seedCaps: seedCapsFrom(input2),
|
|
295305
|
+
openRemediationPrs: await listOpenRemediationPrs(ctx)
|
|
294891
295306
|
});
|
|
294892
295307
|
const cappedBlock = cappedSummary(capped);
|
|
294893
295308
|
log2.info(
|
|
@@ -295522,7 +295937,25 @@ async function runVerifyRemediation(ctx, { concern_ids, download_external_module
|
|
|
295522
295937
|
if (key !== void 0) keyed.push({ id, key });
|
|
295523
295938
|
else unkeyed.push(id);
|
|
295524
295939
|
}
|
|
295525
|
-
const
|
|
295940
|
+
const byKey = partitionByKey(keyed, currentKeys);
|
|
295941
|
+
const read3 = fileReader(cwd);
|
|
295942
|
+
const remainingKeyed = keyed.filter((k) => byKey.remaining.includes(k.id));
|
|
295943
|
+
const atSite = new Set(
|
|
295944
|
+
resolvedAtSite({
|
|
295945
|
+
requested: remainingKeyed.map((k) => ({
|
|
295946
|
+
...k,
|
|
295947
|
+
site: session.siteById?.get(k.id) ?? null,
|
|
295948
|
+
file: reported.get(k.id)?.location.file
|
|
295949
|
+
})),
|
|
295950
|
+
current: currentConcerns.map((c) => ({ key: concernKeyOf(c), site: siteOf(c, read3) })),
|
|
295951
|
+
firstSites: session.firstSitesByKey ?? /* @__PURE__ */ new Map(),
|
|
295952
|
+
declared: (file2) => new Set(declaredAddresses2(read3(file2) ?? ""))
|
|
295953
|
+
})
|
|
295954
|
+
);
|
|
295955
|
+
const keyedVerdict = {
|
|
295956
|
+
resolved: [...byKey.resolved, ...byKey.remaining.filter((id) => atSite.has(id))],
|
|
295957
|
+
remaining: byKey.remaining.filter((id) => !atSite.has(id))
|
|
295958
|
+
};
|
|
295526
295959
|
const fallbackVerdict = computeRemediationVerdict(unkeyed, new Set(currentIds));
|
|
295527
295960
|
const resolved = [...keyedVerdict.resolved, ...fallbackVerdict.resolved];
|
|
295528
295961
|
const remaining = [...keyedVerdict.remaining, ...fallbackVerdict.remaining];
|
|
@@ -298776,15 +299209,15 @@ async function startMcpHttpServer(ctx, options) {
|
|
|
298776
299209
|
|
|
298777
299210
|
// src/mcp/terraform/policyGate.ts
|
|
298778
299211
|
import {
|
|
298779
|
-
existsSync as
|
|
299212
|
+
existsSync as existsSync13,
|
|
298780
299213
|
mkdirSync as mkdirSync7,
|
|
298781
299214
|
mkdtempSync as mkdtempSync7,
|
|
298782
299215
|
readdirSync as readdirSync9,
|
|
298783
|
-
readFileSync as
|
|
299216
|
+
readFileSync as readFileSync35,
|
|
298784
299217
|
writeFileSync as writeFileSync17
|
|
298785
299218
|
} from "node:fs";
|
|
298786
299219
|
import { tmpdir as osTmpdir } from "node:os";
|
|
298787
|
-
import { dirname as dirname8, isAbsolute as isAbsolute6, join as
|
|
299220
|
+
import { dirname as dirname8, isAbsolute as isAbsolute6, join as join58, relative as relative6, resolve as resolve8 } from "node:path";
|
|
298788
299221
|
function coercePolicyRules(raw2) {
|
|
298789
299222
|
const rules = [];
|
|
298790
299223
|
const rejected = [];
|
|
@@ -299036,7 +299469,7 @@ function evaluateRulesStatically(cwd, rules, scope2 = { kind: "all", reason: ""
|
|
|
299036
299469
|
const files = [];
|
|
299037
299470
|
for (const rel of walk.files) {
|
|
299038
299471
|
try {
|
|
299039
|
-
files.push({ rel, text:
|
|
299472
|
+
files.push({ rel, text: readFileSync35(join58(cwd, rel), "utf-8") });
|
|
299040
299473
|
} catch {
|
|
299041
299474
|
}
|
|
299042
299475
|
}
|
|
@@ -299151,16 +299584,16 @@ function cloudEmittedRego(rules) {
|
|
|
299151
299584
|
}
|
|
299152
299585
|
function readOrEmpty(path15) {
|
|
299153
299586
|
try {
|
|
299154
|
-
return
|
|
299587
|
+
return readFileSync35(path15, "utf-8");
|
|
299155
299588
|
} catch {
|
|
299156
299589
|
return "";
|
|
299157
299590
|
}
|
|
299158
299591
|
}
|
|
299159
299592
|
function regoDirIn(root, skip) {
|
|
299160
299593
|
for (const dir of DEFAULT_POLICY_DIRS) {
|
|
299161
|
-
const abs =
|
|
299162
|
-
if (
|
|
299163
|
-
(rel) => !skip(
|
|
299594
|
+
const abs = join58(root, dir);
|
|
299595
|
+
if (existsSync13(abs) && walkFilesBySuffix(abs, ".rego").some(
|
|
299596
|
+
(rel) => !skip(join58(dir, rel), readOrEmpty(join58(abs, rel)))
|
|
299164
299597
|
)) {
|
|
299165
299598
|
return dir;
|
|
299166
299599
|
}
|
|
@@ -299168,14 +299601,14 @@ function regoDirIn(root, skip) {
|
|
|
299168
299601
|
return null;
|
|
299169
299602
|
}
|
|
299170
299603
|
function withoutSkipped(root, dir, skip, tmpdir5) {
|
|
299171
|
-
const abs =
|
|
299172
|
-
const files = readdirSync9(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile()).map((e) => relative6(abs,
|
|
299173
|
-
const kept = files.filter((rel) => !skip(
|
|
299604
|
+
const abs = join58(root, dir);
|
|
299605
|
+
const files = readdirSync9(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile()).map((e) => relative6(abs, join58(e.parentPath, e.name)));
|
|
299606
|
+
const kept = files.filter((rel) => !skip(join58(dir, rel), readOrEmpty(join58(abs, rel))));
|
|
299174
299607
|
if (kept.length === files.length) return abs;
|
|
299175
|
-
const copy =
|
|
299608
|
+
const copy = join58(mkdtempSync7(join58(tmpdir5 ?? osTmpdir(), "policy-own-")), dir);
|
|
299176
299609
|
for (const rel of kept) {
|
|
299177
|
-
mkdirSync7(dirname8(
|
|
299178
|
-
writeFileSync17(
|
|
299610
|
+
mkdirSync7(dirname8(join58(copy, rel)), { recursive: true });
|
|
299611
|
+
writeFileSync17(join58(copy, rel), readFileSync35(join58(abs, rel)));
|
|
299179
299612
|
}
|
|
299180
299613
|
return copy;
|
|
299181
299614
|
}
|
|
@@ -299197,18 +299630,18 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
299197
299630
|
}
|
|
299198
299631
|
const own2 = tree.files.filter((f) => !skip(f.path, f.raw));
|
|
299199
299632
|
if (!own2.some((f) => f.path.endsWith(".rego"))) continue;
|
|
299200
|
-
const root = mkdtempSync7(
|
|
299633
|
+
const root = mkdtempSync7(join58(tmpdir5 ?? osTmpdir(), "policy-base-"));
|
|
299201
299634
|
for (const f of own2) {
|
|
299202
|
-
mkdirSync7(dirname8(
|
|
299203
|
-
writeFileSync17(
|
|
299635
|
+
mkdirSync7(dirname8(join58(root, f.path)), { recursive: true });
|
|
299636
|
+
writeFileSync17(join58(root, f.path), f.raw);
|
|
299204
299637
|
}
|
|
299205
299638
|
const toml = readFileAtBaseRef(cwd, baseRef, CONFTEST_CONFIG);
|
|
299206
|
-
if (toml.kind === "file") writeFileSync17(
|
|
299207
|
-
const same = head === dir && readdirSync9(
|
|
299639
|
+
if (toml.kind === "file") writeFileSync17(join58(root, CONFTEST_CONFIG), toml.raw);
|
|
299640
|
+
const same = head === dir && readdirSync9(join58(cwd, dir), { recursive: true, withFileTypes: true }).filter(
|
|
299208
299641
|
(e) => e.isFile()
|
|
299209
299642
|
).length === tree.files.length && tree.files.every((f) => {
|
|
299210
299643
|
try {
|
|
299211
|
-
return
|
|
299644
|
+
return readFileSync35(join58(cwd, f.path), "utf-8") === f.raw;
|
|
299212
299645
|
} catch {
|
|
299213
299646
|
return false;
|
|
299214
299647
|
}
|
|
@@ -299218,7 +299651,7 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
299218
299651
|
`the Rego policy differs from the base ref (${tree.ref}) \u2014 applying the BASE ${dir}/ so this change cannot relax the policy reviewing it. It takes effect once merged.`
|
|
299219
299652
|
);
|
|
299220
299653
|
}
|
|
299221
|
-
return { policyDir:
|
|
299654
|
+
return { policyDir: join58(root, dir), conftestCwd: root };
|
|
299222
299655
|
}
|
|
299223
299656
|
if (head) {
|
|
299224
299657
|
notes.push(
|
|
@@ -299228,7 +299661,7 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
299228
299661
|
return null;
|
|
299229
299662
|
}
|
|
299230
299663
|
function findWorkflowPlanJson(cwd, notes) {
|
|
299231
|
-
const present = PLAN_JSON_NAMES.filter((name) =>
|
|
299664
|
+
const present = PLAN_JSON_NAMES.filter((name) => existsSync13(join58(cwd, name)));
|
|
299232
299665
|
if (present.length === 0) return null;
|
|
299233
299666
|
const listing = run("git", ["ls-files", "-z"], cwd);
|
|
299234
299667
|
if (listing.status !== 0) {
|
|
@@ -299245,7 +299678,7 @@ function findWorkflowPlanJson(cwd, notes) {
|
|
|
299245
299678
|
);
|
|
299246
299679
|
continue;
|
|
299247
299680
|
}
|
|
299248
|
-
return
|
|
299681
|
+
return join58(cwd, name);
|
|
299249
299682
|
}
|
|
299250
299683
|
return null;
|
|
299251
299684
|
}
|
|
@@ -299275,7 +299708,7 @@ function evaluatePolicyGate(cwd, rawRules, opts = {}) {
|
|
|
299275
299708
|
let plan;
|
|
299276
299709
|
if (planPath) {
|
|
299277
299710
|
try {
|
|
299278
|
-
plan = asPlan(JSON.parse(
|
|
299711
|
+
plan = asPlan(JSON.parse(readFileSync35(planPath, "utf-8")));
|
|
299279
299712
|
} catch {
|
|
299280
299713
|
}
|
|
299281
299714
|
if (!plan) notes.push(`${planPath} is not a Terraform plan JSON \u2014 ignored`);
|
|
@@ -299378,7 +299811,7 @@ function capturePolicyGate(ctx) {
|
|
|
299378
299811
|
if (!result) return;
|
|
299379
299812
|
const workspace = process.env.GITHUB_WORKSPACE ?? cwd;
|
|
299380
299813
|
for (const o of [...result.violations, ...result.inconclusive]) {
|
|
299381
|
-
if (o.file) o.file = posix16(relative6(workspace,
|
|
299814
|
+
if (o.file) o.file = posix16(relative6(workspace, join58(cwd, o.file)));
|
|
299382
299815
|
}
|
|
299383
299816
|
session.policyGate = result;
|
|
299384
299817
|
for (const n of result.notes) log2.warning(`\xBB policy gate: ${n}`);
|
|
@@ -299713,7 +300146,7 @@ var ThinkingTimer = class {
|
|
|
299713
300146
|
// src/agents/claude.ts
|
|
299714
300147
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
299715
300148
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync10, writeFileSync as writeFileSync22 } from "node:fs";
|
|
299716
|
-
import { join as
|
|
300149
|
+
import { join as join67 } from "node:path";
|
|
299717
300150
|
import { performance as performance6 } from "node:perf_hooks";
|
|
299718
300151
|
import { setTimeout as sleep6 } from "node:timers/promises";
|
|
299719
300152
|
|
|
@@ -300073,7 +300506,7 @@ import { readFile as readFile2 } from "node:fs/promises";
|
|
|
300073
300506
|
|
|
300074
300507
|
// src/agents/shared.ts
|
|
300075
300508
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
300076
|
-
import { join as
|
|
300509
|
+
import { join as join59 } from "node:path";
|
|
300077
300510
|
var MAX_STDERR_LINES = 20;
|
|
300078
300511
|
var MAX_POST_RUN_RETRIES = 3;
|
|
300079
300512
|
function getGitStatus() {
|
|
@@ -300110,7 +300543,7 @@ var agent = (input2) => {
|
|
|
300110
300543
|
};
|
|
300111
300544
|
};
|
|
300112
300545
|
function agentHomeEnv(tmpdir5) {
|
|
300113
|
-
return { HOME: tmpdir5, XDG_CONFIG_HOME:
|
|
300546
|
+
return { HOME: tmpdir5, XDG_CONFIG_HOME: join59(tmpdir5, ".config") };
|
|
300114
300547
|
}
|
|
300115
300548
|
function baseAgentEnv(homeEnv, repoDir) {
|
|
300116
300549
|
return { ...process.env, ...homeEnv, PWD: repoDir };
|
|
@@ -300587,9 +301020,9 @@ function shouldRunGraceTurn(params) {
|
|
|
300587
301020
|
}
|
|
300588
301021
|
|
|
300589
301022
|
// src/agents/quotaTokens.ts
|
|
300590
|
-
var
|
|
300591
|
-
function
|
|
300592
|
-
return t.input + t.output + t.cacheWrite + t.cacheRead *
|
|
301023
|
+
var CACHE_READ_WEIGHT2 = 0.1;
|
|
301024
|
+
function quotaTokens2(t) {
|
|
301025
|
+
return t.input + t.output + (t.reasoning ?? 0) + t.cacheWrite + t.cacheRead * CACHE_READ_WEIGHT2;
|
|
300593
301026
|
}
|
|
300594
301027
|
|
|
300595
301028
|
// src/agents/sessionLabeler.ts
|
|
@@ -300913,7 +301346,7 @@ function matchesRouteSentinel(envVar, model) {
|
|
|
300913
301346
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
300914
301347
|
import { mkdirSync as mkdirSync8, rmSync as rmSync10, writeFileSync as writeFileSync18 } from "node:fs";
|
|
300915
301348
|
import { homedir } from "node:os";
|
|
300916
|
-
import { join as
|
|
301349
|
+
import { join as join60 } from "node:path";
|
|
300917
301350
|
var VERTEX_SERVICE_ACCOUNT_JSON_ENV = "VERTEX_SERVICE_ACCOUNT_JSON";
|
|
300918
301351
|
var GOOGLE_APPLICATION_CREDENTIALS_ENV = "GOOGLE_APPLICATION_CREDENTIALS";
|
|
300919
301352
|
var GOOGLE_CLOUD_PROJECT_ENV = "GOOGLE_CLOUD_PROJECT";
|
|
@@ -300937,7 +301370,7 @@ function readProjectIdFromVertexServiceAccountJson() {
|
|
|
300937
301370
|
}
|
|
300938
301371
|
function createSecretDir() {
|
|
300939
301372
|
const base = process.env.INFRAWEAVER_SECRET_HOME || process.env.HOME || homedir();
|
|
300940
|
-
const secretDir =
|
|
301373
|
+
const secretDir = join60(base, `.${PRODUCT_SLUG}`, "secrets", randomUUID9());
|
|
300941
301374
|
mkdirSync8(secretDir, { recursive: true, mode: 448 });
|
|
300942
301375
|
return secretDir;
|
|
300943
301376
|
}
|
|
@@ -300946,7 +301379,7 @@ function materializeVertexCredentials(params) {
|
|
|
300946
301379
|
const blob = process.env[VERTEX_SERVICE_ACCOUNT_JSON_ENV];
|
|
300947
301380
|
if (!blob) return void 0;
|
|
300948
301381
|
const secretDir = createSecretDir();
|
|
300949
|
-
const credentialsPath =
|
|
301382
|
+
const credentialsPath = join60(secretDir, "vertex-sa.json");
|
|
300950
301383
|
writeFileSync18(credentialsPath, blob, { mode: 384 });
|
|
300951
301384
|
process.env[GOOGLE_APPLICATION_CREDENTIALS_ENV] = credentialsPath;
|
|
300952
301385
|
const projectId = readProjectIdFromVertexServiceAccountJson();
|
|
@@ -301082,29 +301515,29 @@ function createProcessOutputActivityTimeout(ctx) {
|
|
|
301082
301515
|
}
|
|
301083
301516
|
|
|
301084
301517
|
// src/utils/prompt/skills.ts
|
|
301085
|
-
import { existsSync as
|
|
301086
|
-
import { dirname as dirname9, join as
|
|
301518
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readFileSync as readFileSync36, writeFileSync as writeFileSync19 } from "node:fs";
|
|
301519
|
+
import { dirname as dirname9, join as join61 } from "node:path";
|
|
301087
301520
|
import { fileURLToPath } from "node:url";
|
|
301088
301521
|
var BUNDLED_SKILL_NAMES = ["terraform-best-practices"];
|
|
301089
301522
|
function resolveSkillPath(name) {
|
|
301090
301523
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
301091
301524
|
const candidates = [
|
|
301092
|
-
|
|
301093
|
-
|
|
301525
|
+
join61(here, "..", "..", "skills", name, "SKILL.md"),
|
|
301526
|
+
join61(here, "skills", name, "SKILL.md")
|
|
301094
301527
|
];
|
|
301095
301528
|
for (const candidate of candidates) {
|
|
301096
|
-
if (
|
|
301529
|
+
if (existsSync14(candidate)) return candidate;
|
|
301097
301530
|
}
|
|
301098
301531
|
throw new Error(`bundled skill not found: ${name} (looked in ${candidates.join(", ")})`);
|
|
301099
301532
|
}
|
|
301100
301533
|
var SKILL_TARGET_DIRS = [".opencode/skills", ".claude/skills", ".agents/skills"];
|
|
301101
301534
|
function installBundledSkills(params) {
|
|
301102
301535
|
for (const name of BUNDLED_SKILL_NAMES) {
|
|
301103
|
-
const content =
|
|
301536
|
+
const content = readFileSync36(resolveSkillPath(name), "utf8");
|
|
301104
301537
|
for (const targetDir of SKILL_TARGET_DIRS) {
|
|
301105
|
-
const skillDir =
|
|
301538
|
+
const skillDir = join61(params.home, targetDir, name);
|
|
301106
301539
|
mkdirSync9(skillDir, { recursive: true });
|
|
301107
|
-
writeFileSync19(
|
|
301540
|
+
writeFileSync19(join61(skillDir, "SKILL.md"), content);
|
|
301108
301541
|
}
|
|
301109
301542
|
}
|
|
301110
301543
|
log2.success(`installed bundled skills: ${BUNDLED_SKILL_NAMES.join(", ")}`);
|
|
@@ -301112,9 +301545,9 @@ function installBundledSkills(params) {
|
|
|
301112
301545
|
|
|
301113
301546
|
// src/utils/setup/install.ts
|
|
301114
301547
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
301115
|
-
import { createHash as
|
|
301116
|
-
import { chmodSync as chmodSync2, createWriteStream as createWriteStream2, existsSync as
|
|
301117
|
-
import { join as
|
|
301548
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
301549
|
+
import { chmodSync as chmodSync2, createWriteStream as createWriteStream2, existsSync as existsSync17, readFileSync as readFileSync37 } from "node:fs";
|
|
301550
|
+
import { join as join66 } from "node:path";
|
|
301118
301551
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
301119
301552
|
|
|
301120
301553
|
// src/utils/setup/tarballCache.ts
|
|
@@ -301169,7 +301602,7 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
301169
301602
|
`Refusing to install ${descriptor}: the registry published no integrity digest (neither dist.integrity nor dist.shasum), so the download cannot be verified.`
|
|
301170
301603
|
);
|
|
301171
301604
|
}
|
|
301172
|
-
const bytes =
|
|
301605
|
+
const bytes = readFileSync37(tarballPath);
|
|
301173
301606
|
if (integrity2) {
|
|
301174
301607
|
const candidates = integrity2.trim().split(/\s+/).filter(Boolean);
|
|
301175
301608
|
for (const candidate of candidates) {
|
|
@@ -301179,7 +301612,7 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
301179
301612
|
const expected = candidate.slice(separator2 + 1);
|
|
301180
301613
|
let actual;
|
|
301181
301614
|
try {
|
|
301182
|
-
actual =
|
|
301615
|
+
actual = createHash15(algorithm).update(bytes).digest("base64");
|
|
301183
301616
|
} catch {
|
|
301184
301617
|
continue;
|
|
301185
301618
|
}
|
|
@@ -301189,7 +301622,7 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
301189
301622
|
`Integrity check FAILED for ${descriptor}: the downloaded tarball does not match the registry's published digest (${integrity2}). Refusing to execute it.`
|
|
301190
301623
|
);
|
|
301191
301624
|
}
|
|
301192
|
-
const actualShasum =
|
|
301625
|
+
const actualShasum = createHash15("sha1").update(bytes).digest("hex");
|
|
301193
301626
|
if (actualShasum !== shasum) {
|
|
301194
301627
|
throw new Error(
|
|
301195
301628
|
`Integrity check FAILED for ${descriptor}: the downloaded tarball does not match the registry's published shasum (expected ${shasum}, got ${actualShasum}). Refusing to execute it.`
|
|
@@ -301198,9 +301631,9 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
301198
301631
|
}
|
|
301199
301632
|
async function installFromNpmTarball(params) {
|
|
301200
301633
|
const tempDir = getTempDir();
|
|
301201
|
-
const extractedDir =
|
|
301202
|
-
const cliPath =
|
|
301203
|
-
if (
|
|
301634
|
+
const extractedDir = join66(tempDir, "package");
|
|
301635
|
+
const cliPath = join66(extractedDir, params.executablePath);
|
|
301636
|
+
if (existsSync17(cliPath)) {
|
|
301204
301637
|
log2.debug(`\xBB using cached binary at ${cliPath}`);
|
|
301205
301638
|
return cliPath;
|
|
301206
301639
|
}
|
|
@@ -301251,7 +301684,7 @@ async function installFromNpmTarball(params) {
|
|
|
301251
301684
|
dist = (await manifestResponse.json()).dist;
|
|
301252
301685
|
}
|
|
301253
301686
|
log2.debug(`\xBB installing ${params.packageName}@${resolvedVersion}...`);
|
|
301254
|
-
const tarballPath =
|
|
301687
|
+
const tarballPath = join66(tempDir, "package.tgz");
|
|
301255
301688
|
const tarballFileName = params.packageName.startsWith("@") ? params.packageName.split("/")[1] : params.packageName;
|
|
301256
301689
|
const tarballUrl = `${npmRegistry}/${encodedName}/-/${tarballFileName}-${resolvedVersion}.tgz`;
|
|
301257
301690
|
const restored = await restoreTarball({
|
|
@@ -301291,7 +301724,7 @@ async function installFromNpmTarball(params) {
|
|
|
301291
301724
|
`Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}`
|
|
301292
301725
|
);
|
|
301293
301726
|
}
|
|
301294
|
-
if (!
|
|
301727
|
+
if (!existsSync17(cliPath)) {
|
|
301295
301728
|
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
301296
301729
|
}
|
|
301297
301730
|
if (params.installDependencies) {
|
|
@@ -301402,9 +301835,9 @@ var CLAUDE_DISALLOWED_TOOLS = CLAUDE_EXEC_TOOL_DENY_RULES.join(",");
|
|
|
301402
301835
|
var INFRAWEAVER_MCP_AUTH_HEADER = `Bearer \${${MCP_SERVER_TOKEN_ENV}}`;
|
|
301403
301836
|
var CLAUDE_MAX_CONCURRENT_SUBAGENTS_DEFAULT = "4";
|
|
301404
301837
|
function writeMcpConfig(ctx) {
|
|
301405
|
-
const configDir =
|
|
301838
|
+
const configDir = join67(ctx.tmpdir, ".claude");
|
|
301406
301839
|
mkdirSync10(configDir, { recursive: true });
|
|
301407
|
-
const configPath =
|
|
301840
|
+
const configPath = join67(configDir, "mcp.json");
|
|
301408
301841
|
const terraformMcp = resolveTerraformMcp(ctx.payload);
|
|
301409
301842
|
if (terraformMcp.kind === "docker_missing") log2.info(`\xBB ${terraformMcp.note}`);
|
|
301410
301843
|
const opentofuMcp = resolveOpenTofuMcp(ctx.payload);
|
|
@@ -301436,13 +301869,13 @@ function writeMcpConfig(ctx) {
|
|
|
301436
301869
|
return configPath;
|
|
301437
301870
|
}
|
|
301438
301871
|
function writePretoolGateAssets(ctx, stopHookPath) {
|
|
301439
|
-
const scriptPath =
|
|
301872
|
+
const scriptPath = join67(ctx.tmpdir, CLAUDE_PRETOOL_GATE_FILENAME);
|
|
301440
301873
|
writeFileSync22(
|
|
301441
301874
|
scriptPath,
|
|
301442
301875
|
buildClaudePretoolGateSource(ctx.subagentDeniedTools, writePolicyPath2(ctx.tmpdir))
|
|
301443
301876
|
);
|
|
301444
301877
|
chmodSync3(scriptPath, 493);
|
|
301445
|
-
const settingsPath =
|
|
301878
|
+
const settingsPath = join67(ctx.tmpdir, "infraweaver-claude-settings.json");
|
|
301446
301879
|
const settings = buildClaudePretoolGateSettings(scriptPath, CLAUDE_EXEC_TOOL_DENY_RULES);
|
|
301447
301880
|
settings.permissions.deny.push(...harnessTmpdirWriteDenyClaude(ctx.tmpdir));
|
|
301448
301881
|
if (stopHookPath) {
|
|
@@ -301531,7 +301964,7 @@ function timerFor(state5, label) {
|
|
|
301531
301964
|
function chargeTokenQuota(state5) {
|
|
301532
301965
|
const quota = state5.params.tokenQuota;
|
|
301533
301966
|
if (!quota || state5.stopRun.signal.aborted) return;
|
|
301534
|
-
if (!quota.observe(state5.quotaSource,
|
|
301967
|
+
if (!quota.observe(state5.quotaSource, quotaTokens2(state5.accumulatedTokens))) return;
|
|
301535
301968
|
log2.info(`\xBB ${state5.params.label}: ${quota.gap()}`);
|
|
301536
301969
|
state5.stopRun.abort(new TokenQuotaExceededError(quota.gap()));
|
|
301537
301970
|
}
|
|
@@ -302067,11 +302500,11 @@ var claude = agent({
|
|
|
302067
302500
|
const onVertex = matchesRouteSentinel(VERTEX_MODEL_ID_ENV, specifier) && specifier !== void 0 && isVertexAnthropicId(specifier);
|
|
302068
302501
|
const model = !specifier ? void 0 : onBedrock ? specifier : onVertex ? void 0 : stripProviderPrefix(specifier);
|
|
302069
302502
|
const homeEnv = agentHomeEnv(ctx.tmpdir);
|
|
302070
|
-
mkdirSync10(
|
|
302503
|
+
mkdirSync10(join67(homeEnv.XDG_CONFIG_HOME, "claude"), { recursive: true });
|
|
302071
302504
|
installBundledSkills({ home: homeEnv.HOME });
|
|
302072
302505
|
const mcpConfigPath = writeMcpConfig(ctx);
|
|
302073
302506
|
const effort = resolveEffort(model);
|
|
302074
|
-
const stopHookPath =
|
|
302507
|
+
const stopHookPath = join67(ctx.tmpdir, "infraweaver-stop-hook.sh");
|
|
302075
302508
|
writeFileSync22(stopHookPath, buildStopHookScript(), { mode: 493 });
|
|
302076
302509
|
const pretoolGate = writePretoolGateAssets(ctx, stopHookPath);
|
|
302077
302510
|
installManagedSettings({
|
|
@@ -302237,7 +302670,7 @@ var claude = agent({
|
|
|
302237
302670
|
init_core3();
|
|
302238
302671
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
302239
302672
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync24 } from "node:fs";
|
|
302240
|
-
import { join as
|
|
302673
|
+
import { join as join69 } from "node:path";
|
|
302241
302674
|
import { performance as performance7 } from "node:perf_hooks";
|
|
302242
302675
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
302243
302676
|
import { setTimeout as sleep7 } from "node:timers/promises";
|
|
@@ -307920,7 +308353,7 @@ function autoSelectModel() {
|
|
|
307920
308353
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
307921
308354
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync23 } from "node:fs";
|
|
307922
308355
|
import { homedir as homedir3, userInfo as userInfo2 } from "node:os";
|
|
307923
|
-
import { join as
|
|
308356
|
+
import { join as join68 } from "node:path";
|
|
307924
308357
|
|
|
307925
308358
|
// src/utils/agent/codexOAuth.ts
|
|
307926
308359
|
init_webapi();
|
|
@@ -307974,8 +308407,8 @@ function installCodexAuth() {
|
|
|
307974
308407
|
}
|
|
307975
308408
|
const expiresMs = decodeJwtExpMs(body2.tokens.access_token) ?? 0;
|
|
307976
308409
|
const xdgDataHome = resolveDataHome();
|
|
307977
|
-
const opencodeDir =
|
|
307978
|
-
const authPath =
|
|
308410
|
+
const opencodeDir = join68(xdgDataHome, "opencode");
|
|
308411
|
+
const authPath = join68(opencodeDir, "auth.json");
|
|
307979
308412
|
const opencodeAuth = {
|
|
307980
308413
|
openai: {
|
|
307981
308414
|
type: "oauth",
|
|
@@ -307999,7 +308432,7 @@ function installCodexAuth() {
|
|
|
307999
308432
|
};
|
|
308000
308433
|
}
|
|
308001
308434
|
function resolveDataHome() {
|
|
308002
|
-
if (process.env.CI !== "true") return
|
|
308435
|
+
if (process.env.CI !== "true") return join68(homedir3(), ".local", "share");
|
|
308003
308436
|
bootstrapInfraweaverDataDir();
|
|
308004
308437
|
return INFRAWEAVER_DATA_DIR;
|
|
308005
308438
|
}
|
|
@@ -308263,7 +308696,7 @@ function newTurn() {
|
|
|
308263
308696
|
turnCounter += 1;
|
|
308264
308697
|
return {
|
|
308265
308698
|
finalText: "",
|
|
308266
|
-
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
308699
|
+
tokens: { input: 0, output: 0, reasoning: 0, cacheRead: 0, cacheWrite: 0 },
|
|
308267
308700
|
costUsd: 0,
|
|
308268
308701
|
sessionError: null,
|
|
308269
308702
|
lastToolError: null,
|
|
@@ -308273,7 +308706,7 @@ function newTurn() {
|
|
|
308273
308706
|
function chargeTokenQuota2(ctx) {
|
|
308274
308707
|
const quota = ctx.tokenQuota;
|
|
308275
308708
|
if (!quota || !ctx.currentTurn || ctx.tokenQuotaExceeded) return;
|
|
308276
|
-
if (!quota.observe(ctx.currentTurn.quotaSource,
|
|
308709
|
+
if (!quota.observe(ctx.currentTurn.quotaSource, quotaTokens2(ctx.currentTurn.tokens))) return;
|
|
308277
308710
|
ctx.tokenQuotaExceeded = true;
|
|
308278
308711
|
log2.info(`\xBB ${ctx.label}: ${quota.gap()}`);
|
|
308279
308712
|
ctx.abortRun?.(new TokenQuotaExceededError(quota.gap()));
|
|
@@ -308382,6 +308815,7 @@ async function onPartUpdated(ctx, part) {
|
|
|
308382
308815
|
if (t) {
|
|
308383
308816
|
ctx.currentTurn.tokens.input += t.input || 0;
|
|
308384
308817
|
ctx.currentTurn.tokens.output += t.output || 0;
|
|
308818
|
+
ctx.currentTurn.tokens.reasoning += t.reasoning || 0;
|
|
308385
308819
|
ctx.currentTurn.tokens.cacheRead += t.cache?.read || 0;
|
|
308386
308820
|
ctx.currentTurn.tokens.cacheWrite += t.cache?.write || 0;
|
|
308387
308821
|
}
|
|
@@ -308740,10 +309174,10 @@ var opencode = agent({
|
|
|
308740
309174
|
const openAiCompatModel = resolveOpenAiCompatibleOpenCodeModel(rawModel);
|
|
308741
309175
|
const model = isBedrockRoute ? `amazon-bedrock/${rawModel}` : vertexModel ?? openAiCompatModel ?? rawModel;
|
|
308742
309176
|
const homeEnv = agentHomeEnv(ctx.tmpdir);
|
|
308743
|
-
const opencodePluginDir =
|
|
309177
|
+
const opencodePluginDir = join69(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
308744
309178
|
mkdirSync12(opencodePluginDir, { recursive: true });
|
|
308745
309179
|
writeFileSync24(
|
|
308746
|
-
|
|
309180
|
+
join69(opencodePluginDir, INFRAWEAVER_OPENCODE_GATE_PLUGIN_FILENAME),
|
|
308747
309181
|
buildOpencodeSubagentGateSource(ctx.subagentDeniedTools, writePolicyPath2(ctx.tmpdir))
|
|
308748
309182
|
);
|
|
308749
309183
|
installBundledSkills({ home: homeEnv.HOME });
|
|
@@ -308986,10 +309420,10 @@ var DispatchRecorder = class {
|
|
|
308986
309420
|
* orchestrator counts as subagent — including a session the labeler could not
|
|
308987
309421
|
* name, because an unnamed session is by definition not the orchestrator's.
|
|
308988
309422
|
*/
|
|
308989
|
-
recordTokens(label,
|
|
308990
|
-
if (!Number.isFinite(
|
|
308991
|
-
if (label === ORCHESTRATOR_LABEL) this.#orchestratorTokens +=
|
|
308992
|
-
else this.#subagentTokens +=
|
|
309423
|
+
recordTokens(label, billableTokens) {
|
|
309424
|
+
if (!Number.isFinite(billableTokens) || billableTokens <= 0) return;
|
|
309425
|
+
if (label === ORCHESTRATOR_LABEL) this.#orchestratorTokens += billableTokens;
|
|
309426
|
+
else this.#subagentTokens += billableTokens;
|
|
308993
309427
|
}
|
|
308994
309428
|
tally() {
|
|
308995
309429
|
return {
|
|
@@ -309779,7 +310213,7 @@ async function fetchRunContext(params) {
|
|
|
309779
310213
|
// src/utils/github/github.ts
|
|
309780
310214
|
init_core3();
|
|
309781
310215
|
import { rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
309782
|
-
import { dirname as dirname12, join as
|
|
310216
|
+
import { dirname as dirname12, join as join70 } from "node:path";
|
|
309783
310217
|
|
|
309784
310218
|
// node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
|
|
309785
310219
|
function getUserAgent2() {
|
|
@@ -309878,8 +310312,8 @@ function addQueryParameters(url5, parameters) {
|
|
|
309878
310312
|
}).join("&");
|
|
309879
310313
|
}
|
|
309880
310314
|
var urlVariableRegex = /\{[^{}}]+\}/g;
|
|
309881
|
-
function removeNonChars(
|
|
309882
|
-
return
|
|
310315
|
+
function removeNonChars(variableName2) {
|
|
310316
|
+
return variableName2.replace(/(?:^\W+)|(?:(?<!\W)\W+$)/g, "").split(/,/);
|
|
309883
310317
|
}
|
|
309884
310318
|
function extractUrlVariableNames(url5) {
|
|
309885
310319
|
const matches2 = url5.match(urlVariableRegex);
|
|
@@ -315595,7 +316029,7 @@ function getGitHubUsageSummary() {
|
|
|
315595
316029
|
}
|
|
315596
316030
|
async function writeGitHubUsageSummaryToFile(path15) {
|
|
315597
316031
|
const summary2 = getGitHubUsageSummary();
|
|
315598
|
-
const tmpPath =
|
|
316032
|
+
const tmpPath = join70(dirname12(path15), `.usage-summary-${process.pid}.tmp`);
|
|
315599
316033
|
await writeFile2(tmpPath, JSON.stringify(summary2));
|
|
315600
316034
|
await rename2(tmpPath, path15);
|
|
315601
316035
|
}
|
|
@@ -316140,7 +316574,7 @@ async function resolveModelAndAuth(params) {
|
|
|
316140
316574
|
// src/utils/run/runLifecycle.ts
|
|
316141
316575
|
init_core3();
|
|
316142
316576
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
316143
|
-
import { join as
|
|
316577
|
+
import { join as join73, resolve as resolve10 } from "node:path";
|
|
316144
316578
|
|
|
316145
316579
|
// src/utils/cloud/cloudReport.ts
|
|
316146
316580
|
init_core3();
|
|
@@ -316534,7 +316968,7 @@ async function reportToCloud(input2) {
|
|
|
316534
316968
|
|
|
316535
316969
|
// src/utils/cloud/learnings.ts
|
|
316536
316970
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
316537
|
-
import { dirname as dirname13, join as
|
|
316971
|
+
import { dirname as dirname13, join as join71 } from "node:path";
|
|
316538
316972
|
|
|
316539
316973
|
// src/utils/cloud/learningsTruncate.ts
|
|
316540
316974
|
var MAX_LEARNINGS_LENGTH = 1e5;
|
|
@@ -316551,7 +316985,7 @@ function truncateAtLineBoundary(body2, cap2) {
|
|
|
316551
316985
|
// src/utils/cloud/learnings.ts
|
|
316552
316986
|
var LEARNINGS_FILE_NAME = LEARNINGS_FILE;
|
|
316553
316987
|
function learningsFilePath(tmpdir5) {
|
|
316554
|
-
return
|
|
316988
|
+
return join71(tmpdir5, LEARNINGS_FILE_NAME);
|
|
316555
316989
|
}
|
|
316556
316990
|
async function seedLearningsFile(params) {
|
|
316557
316991
|
const path15 = learningsFilePath(params.tmpdir);
|
|
@@ -316682,7 +317116,7 @@ ${ctx.error}` : ctx.error;
|
|
|
316682
317116
|
|
|
316683
317117
|
// src/utils/github/prSummary.ts
|
|
316684
317118
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
316685
|
-
import { dirname as dirname14, join as
|
|
317119
|
+
import { dirname as dirname14, join as join72 } from "node:path";
|
|
316686
317120
|
var SUMMARY_FILE_NAME = SUMMARY_FILE;
|
|
316687
317121
|
var SUMMARY_SCAFFOLD = `# PR summary
|
|
316688
317122
|
|
|
@@ -316692,7 +317126,7 @@ var SUMMARY_SCAFFOLD = `# PR summary
|
|
|
316692
317126
|
var MIN_SNAPSHOT_LENGTH = 60;
|
|
316693
317127
|
var MAX_SNAPSHOT_LENGTH = 32768;
|
|
316694
317128
|
function summaryFilePath(tmpdir5) {
|
|
316695
|
-
return
|
|
317129
|
+
return join72(tmpdir5, SUMMARY_FILE_NAME);
|
|
316696
317130
|
}
|
|
316697
317131
|
async function seedSummaryFile(params) {
|
|
316698
317132
|
const path15 = summaryFilePath(params.tmpdir);
|
|
@@ -317226,7 +317660,7 @@ async function emitFindingsOutputs(toolState, requiredControls) {
|
|
|
317226
317660
|
if (a.level === "error") error62(a.message, props);
|
|
317227
317661
|
else warning(a.message, props);
|
|
317228
317662
|
}
|
|
317229
|
-
const sarifPath =
|
|
317663
|
+
const sarifPath = join73(workspace, SARIF_FILE);
|
|
317230
317664
|
if (session.emittedSarifPath && resolve10(session.emittedSarifPath) === resolve10(sarifPath)) {
|
|
317231
317665
|
log2.info(`\xBB findings output: replacing the agent-emitted ${SARIF_FILE} with the gate's`);
|
|
317232
317666
|
}
|
|
@@ -317558,7 +317992,7 @@ async function runAgentWithWatchdogs(params) {
|
|
|
317558
317992
|
const tokenQuota = reserved ? quotas.token : createTokenQuota(quotas.tokenLimit.full);
|
|
317559
317993
|
const costQuota = reserved ? quotas.cost : createCostQuota(quotas.costLimit.full);
|
|
317560
317994
|
log2.info(
|
|
317561
|
-
quotas.tokenLimit.full > 0 ? `\xBB run token quota: ${quotas.tokenLimit.full.toLocaleString("en-GB")}
|
|
317995
|
+
quotas.tokenLimit.full > 0 ? `\xBB run token quota: ${quotas.tokenLimit.full.toLocaleString("en-GB")} tokens` + (reserved ? ` (${tokenQuota.limit.toLocaleString("en-GB")} for the run, the rest reserved to deliver findings if it runs out)` : "") + "; a token read from the prompt cache counts as a tenth" : `\xBB run token quota: disabled (${RUN_TOKEN_QUOTA_INPUT}: 0)`
|
|
317562
317996
|
);
|
|
317563
317997
|
log2.info(
|
|
317564
317998
|
quotas.costLimit.full > 0 ? `\xBB run cost quota: $${quotas.costLimit.full.toFixed(2)}` + (reserved ? ` ($${costQuota.limit.toFixed(2)} for the run, the rest reserved to deliver findings if it runs out)` : "") : `\xBB run cost quota: disabled (${RUN_COST_QUOTA_INPUT}: 0)`
|
|
@@ -317656,9 +318090,9 @@ async function runAgentWithWatchdogs(params) {
|
|
|
317656
318090
|
}
|
|
317657
318091
|
|
|
317658
318092
|
// src/phases/startToolPlane.ts
|
|
317659
|
-
import { existsSync as
|
|
318093
|
+
import { existsSync as existsSync18, readdirSync as readdirSync10 } from "node:fs";
|
|
317660
318094
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
317661
|
-
import { join as
|
|
318095
|
+
import { join as join74 } from "node:path";
|
|
317662
318096
|
|
|
317663
318097
|
// src/utils/cloud/runTerminalStatus.ts
|
|
317664
318098
|
var TERMINAL_STATE_KEY = "run_terminal";
|
|
@@ -318486,8 +318920,8 @@ ${instructions.user}` : null,
|
|
|
318486
318920
|
log2.info(instructions.full);
|
|
318487
318921
|
});
|
|
318488
318922
|
if (toolContext.agentId === "opencode") {
|
|
318489
|
-
const pluginDir =
|
|
318490
|
-
const hasPlugins =
|
|
318923
|
+
const pluginDir = join74(process.cwd(), ".opencode", "plugin");
|
|
318924
|
+
const hasPlugins = existsSync18(pluginDir) && readdirSync10(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
318491
318925
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
318492
318926
|
log2.info(
|
|
318493
318927
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|