infraweaver 0.3.10 → 0.3.12
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/quotaTokens.d.ts +8 -0
- package/dist/cli.mjs +1929 -1608
- package/dist/index.js +568 -250
- package/dist/internal.js +6 -4
- package/dist/mcp/crosswalk-digest.d.ts +1 -1
- package/dist/mcp/git.d.ts +19 -3
- package/dist/mcp/localContext.d.ts +9 -1
- package/dist/mcp/shell.d.ts +3 -3
- package/dist/mcp/staleFix.d.ts +13 -1
- package/dist/mcp/terraform/awsPrices.d.ts +1 -1
- package/dist/mcp/terraform/azurePrices.d.ts +1 -1
- package/dist/mcp/terraform/hardcodedSecrets.d.ts +49 -0
- package/dist/mcp/terraform/nativeRules.d.ts +1 -0
- package/dist/mcp/terraform/refactorScope.d.ts +12 -0
- package/dist/mcp/terraform/scanSession.d.ts +2 -0
- package/dist/mcp/terraform/tools/scan.d.ts +1 -0
- package/dist/mcp/terraform/types.d.ts +3 -0
- package/dist/mcp/terraform/verifySites.d.ts +48 -0
- package/dist/utils/config/payload.d.ts +2 -0
- package/package.json +1 -1
- package/src/agents/claude.ts +2 -1
- package/src/agents/opencode.ts +2 -1
- package/src/agents/quotaTokens.ts +25 -0
- package/src/mcp/crosswalk-digest.ts +1 -1
- package/src/mcp/crosswalk.ts +2 -0
- package/src/mcp/git.ts +44 -3
- package/src/mcp/localContext.ts +8 -0
- package/src/mcp/localServer.ts +3 -0
- package/src/mcp/moduleExtraction.ts +4 -1
- package/src/mcp/shell.ts +2 -2
- package/src/mcp/staleFix.ts +21 -2
- package/src/mcp/terraform/awsPrices.ts +1 -1
- package/src/mcp/terraform/azurePrices.ts +23 -23
- package/src/mcp/terraform/concernResult.ts +26 -4
- package/src/mcp/terraform/hardcodedSecrets.ts +202 -0
- package/src/mcp/terraform/nativeRuleScanners.ts +8 -0
- package/src/mcp/terraform/nativeRules.ts +14 -0
- package/src/mcp/terraform/refactorScope.ts +86 -0
- package/src/mcp/terraform/scanSession.ts +6 -0
- package/src/mcp/terraform/standardsReport.ts +2 -0
- package/src/mcp/terraform/tools/consolidationCandidates.ts +5 -1
- package/src/mcp/terraform/tools/normalizationCandidates.ts +5 -1
- package/src/mcp/terraform/tools/verifyRemediation.ts +23 -1
- package/src/mcp/terraform/types.ts +3 -0
- package/src/mcp/terraform/verifySites.ts +106 -0
- package/src/modes/refactor.ts +2 -0
- package/src/modes/refresh-remediation.ts +1 -1
- package/src/modes/remediate-and-refactor.ts +1 -1
- package/src/modes/remediate.ts +2 -2
- package/src/utils/config/payload.ts +4 -0
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 });
|
|
@@ -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 existsSync17, 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 (existsSync17(systemTar)) {
|
|
160398
160398
|
return { path: systemTar, type: ArchiveToolType.BSD };
|
|
160399
160399
|
}
|
|
160400
160400
|
break;
|
|
@@ -258516,7 +258516,7 @@ var declare = ark.declare;
|
|
|
258516
258516
|
import { createHash as createHash4 } from "node:crypto";
|
|
258517
258517
|
|
|
258518
258518
|
// src/mcp/crosswalk-digest.ts
|
|
258519
|
-
var EXPECTED_CROSSWALK_DIGEST = "
|
|
258519
|
+
var EXPECTED_CROSSWALK_DIGEST = "f583001997c4c69f84f189a14e69e4f6eb2c52bddc04ca7f404286b5280d1ff4";
|
|
258520
258520
|
|
|
258521
258521
|
// node_modules/.pnpm/@infraweaver-io+crosswalk@1.2.0/node_modules/@infraweaver-io/crosswalk/dist/frameworks.js
|
|
258522
258522
|
var FRAMEWORKS = [
|
|
@@ -259020,9 +259020,9 @@ function boxString(text, options) {
|
|
|
259020
259020
|
if (line.length <= maxWidth - padding * 2) {
|
|
259021
259021
|
wrappedLines.push(line);
|
|
259022
259022
|
} else {
|
|
259023
|
-
const
|
|
259023
|
+
const words2 = line.split(" ");
|
|
259024
259024
|
let currentLine = "";
|
|
259025
|
-
for (const word of
|
|
259025
|
+
for (const word of words2) {
|
|
259026
259026
|
const testLine = currentLine ? `${currentLine} ${word}` : word;
|
|
259027
259027
|
if (testLine.length <= maxWidth - padding * 2) {
|
|
259028
259028
|
currentLine = testLine;
|
|
@@ -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.12",
|
|
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",
|
|
@@ -260156,6 +260156,7 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
260156
260156
|
var NATIVE_SOURCE = TOOL_NAME;
|
|
260157
260157
|
var SECRET_PERSISTED_TO_STATE = "secret-persisted-to-state";
|
|
260158
260158
|
var COMMITTED_STATE_FILE = "committed-state-file";
|
|
260159
|
+
var HARDCODED_SECRET_ARGUMENT = "hardcoded-secret-argument";
|
|
260159
260160
|
var IMPERATIVE_ACTION_TRIGGER = "imperative-action-trigger";
|
|
260160
260161
|
var DYNAMIC_DESTROY_PROTECTION = "dynamic-destroy-protection";
|
|
260161
260162
|
var DEPRECATED_STATE_LOCKING = "deprecated-state-locking";
|
|
@@ -260191,6 +260192,14 @@ var NATIVE_RULES = [
|
|
|
260191
260192
|
asserts: "git tracks a `.tfstate` / `.tfstate.backup` file at this path, so the plaintext record of every attribute Terraform read back from the provider is in the history of every clone and fork",
|
|
260192
260193
|
doesNotAssert: "that the state contains a live credential, or that anyone has read it \u2014 the file is never opened; the finding is that state is under version control, and what it recorded is for the owner to say"
|
|
260193
260194
|
},
|
|
260195
|
+
{
|
|
260196
|
+
id: HARDCODED_SECRET_ARGUMENT,
|
|
260197
|
+
title: "Credential written into the configuration as a literal",
|
|
260198
|
+
band: "verified",
|
|
260199
|
+
category: "security",
|
|
260200
|
+
asserts: "an argument, map key or variable whose name says it holds a credential (`password`, `token`, `client_secret`, `api_key`, \u2026) is assigned a string literal, so the value is in the repository and in its history",
|
|
260201
|
+
doesNotAssert: "that the value is a live credential \u2014 it may be a test value; the finding is that a credential slot is filled from the code rather than at run time"
|
|
260202
|
+
},
|
|
260194
260203
|
{
|
|
260195
260204
|
id: IMPERATIVE_ACTION_TRIGGER,
|
|
260196
260205
|
title: "Imperative side-effect invoked from declarative IaC (action / action_trigger)",
|
|
@@ -261515,7 +261524,9 @@ var THEME_LOCKED = /* @__PURE__ */ new Map([
|
|
|
261515
261524
|
// credentials", and state in git is the canonical failure of it. It deliberately
|
|
261516
261525
|
// does NOT also cite `encryption-at-rest`: whether the repository is encrypted is
|
|
261517
261526
|
// not what the finding establishes.
|
|
261518
|
-
["committed-state-file", "secrets-management"]
|
|
261527
|
+
["committed-state-file", "secrets-management"],
|
|
261528
|
+
// a credential in the code is the same CIS 16.4 failure one step earlier than state in git
|
|
261529
|
+
["hardcoded-secret-argument", "secrets-management"]
|
|
261519
261530
|
]);
|
|
261520
261531
|
function bareRuleId(ruleId) {
|
|
261521
261532
|
const colon = ruleId.indexOf(":");
|
|
@@ -266086,6 +266097,128 @@ function scanDialect(files) {
|
|
|
266086
266097
|
return concerns;
|
|
266087
266098
|
}
|
|
266088
266099
|
|
|
266100
|
+
// src/mcp/terraform/hardcodedSecrets.ts
|
|
266101
|
+
var SECRET_WORDS = /* @__PURE__ */ new Set([
|
|
266102
|
+
"password",
|
|
266103
|
+
"passwd",
|
|
266104
|
+
"pwd",
|
|
266105
|
+
"passphrase",
|
|
266106
|
+
"secret",
|
|
266107
|
+
"token",
|
|
266108
|
+
"auth",
|
|
266109
|
+
"apikey",
|
|
266110
|
+
"credential",
|
|
266111
|
+
"credentials"
|
|
266112
|
+
]);
|
|
266113
|
+
var SECRET_KEY_PREFIXES = /* @__PURE__ */ new Set(["api", "secret", "private", "signing"]);
|
|
266114
|
+
var NOT_SECRET_TOKENS = /* @__PURE__ */ new Set(["creation", "idempotency", "client", "request", "continuation"]);
|
|
266115
|
+
function words(name) {
|
|
266116
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase().split(/[_-]+/).filter(Boolean);
|
|
266117
|
+
}
|
|
266118
|
+
function isSecretName(name) {
|
|
266119
|
+
const w = words(name);
|
|
266120
|
+
const last = w.at(-1);
|
|
266121
|
+
const prev = w.at(-2);
|
|
266122
|
+
if (last === void 0) return false;
|
|
266123
|
+
if (last === "key") return prev !== void 0 && SECRET_KEY_PREFIXES.has(prev);
|
|
266124
|
+
if (last === "token" && prev !== void 0 && NOT_SECRET_TOKENS.has(prev)) return false;
|
|
266125
|
+
return SECRET_WORDS.has(last);
|
|
266126
|
+
}
|
|
266127
|
+
function isPlaceholder(inner) {
|
|
266128
|
+
return inner.trim() === "" || /^[*xX.]+$/.test(inner) || /^<[^>]*>$/.test(inner) || // the dummy credentials offline plans and LocalStack are given (`secret_key = "test"`)
|
|
266129
|
+
/^(?:test|mock|fake|dummy|fixture|example|placeholder|sample)(?:[_-].*)?$/i.test(inner) || // a token's lifetime unit: `token_validity_units { access_token = "hours" }`
|
|
266130
|
+
/^(?:seconds|minutes|hours|days)$/.test(inner);
|
|
266131
|
+
}
|
|
266132
|
+
var HEADER = /^(resource|data|provider|module|locals|variable|output|terraform)\b([^{]*)\{\s*$/;
|
|
266133
|
+
var ASSIGNMENT = /^\s*(?:"([A-Za-z_][\w-]*)"|([A-Za-z_][\w-]*))\s*=(?!=)\s*(.*)$/;
|
|
266134
|
+
var HEREDOC = /<<-?([A-Za-z_]\w*)\s*$/;
|
|
266135
|
+
var INLINE_PAIR = /(?:"([A-Za-z_][\w-]*)"|\b([A-Za-z_][\w-]*))\s*=(?!=)\s*("(?:[^"\\]|\\.)*")/g;
|
|
266136
|
+
function literalValue(raw2) {
|
|
266137
|
+
const value2 = stripTrailingComment(raw2).replace(/,$/, "").trim();
|
|
266138
|
+
return isStringLiteral(value2) && !isPlaceholder(value2.slice(1, -1));
|
|
266139
|
+
}
|
|
266140
|
+
function findHardcodedSecrets(hcl2) {
|
|
266141
|
+
const out = [];
|
|
266142
|
+
let holder = null;
|
|
266143
|
+
let heredoc = null;
|
|
266144
|
+
let inComment = false;
|
|
266145
|
+
const lines = hcl2.split("\n");
|
|
266146
|
+
for (let i = 0; i < lines.length; i++) {
|
|
266147
|
+
const line = lines[i].replace(/\r$/, "");
|
|
266148
|
+
if (heredoc !== null) {
|
|
266149
|
+
if (line.trim() === heredoc) heredoc = null;
|
|
266150
|
+
continue;
|
|
266151
|
+
}
|
|
266152
|
+
if (inComment) {
|
|
266153
|
+
if (line.includes("*/")) inComment = false;
|
|
266154
|
+
continue;
|
|
266155
|
+
}
|
|
266156
|
+
const trimmed = line.trimStart();
|
|
266157
|
+
if (trimmed.startsWith("/*")) {
|
|
266158
|
+
inComment = !trimmed.includes("*/");
|
|
266159
|
+
continue;
|
|
266160
|
+
}
|
|
266161
|
+
if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
|
|
266162
|
+
const header = HEADER.exec(line);
|
|
266163
|
+
if (header) {
|
|
266164
|
+
holder = `${header[1]}${header[2].trimEnd() ? ` ${header[2].trim()}` : ""}`;
|
|
266165
|
+
continue;
|
|
266166
|
+
}
|
|
266167
|
+
if (line.startsWith("}")) {
|
|
266168
|
+
holder = null;
|
|
266169
|
+
continue;
|
|
266170
|
+
}
|
|
266171
|
+
const opens = HEREDOC.exec(line);
|
|
266172
|
+
if (opens) heredoc = opens[1];
|
|
266173
|
+
if (holder === null || opens) continue;
|
|
266174
|
+
const m = ASSIGNMENT.exec(line);
|
|
266175
|
+
if (!m) continue;
|
|
266176
|
+
const name = m[1] ?? m[2];
|
|
266177
|
+
const value2 = m[3];
|
|
266178
|
+
if (holder.startsWith("variable ")) {
|
|
266179
|
+
const variable = /^variable\s+"?([\w-]+)"?/.exec(holder)?.[1] ?? "";
|
|
266180
|
+
if (name === "default" && isSecretName(variable) && literalValue(value2)) {
|
|
266181
|
+
out.push({ name: variable, holder, line: i + 1 });
|
|
266182
|
+
}
|
|
266183
|
+
continue;
|
|
266184
|
+
}
|
|
266185
|
+
if (holder.startsWith("output ") || holder.startsWith("terraform")) continue;
|
|
266186
|
+
if (isSecretName(name) && literalValue(value2)) {
|
|
266187
|
+
out.push({ name, holder, line: i + 1 });
|
|
266188
|
+
continue;
|
|
266189
|
+
}
|
|
266190
|
+
for (const pair of value2.matchAll(INLINE_PAIR)) {
|
|
266191
|
+
const key = pair[1] ?? pair[2];
|
|
266192
|
+
if (isSecretName(key) && literalValue(pair[3])) {
|
|
266193
|
+
out.push({ name: key, holder, line: i + 1 });
|
|
266194
|
+
}
|
|
266195
|
+
}
|
|
266196
|
+
}
|
|
266197
|
+
return out;
|
|
266198
|
+
}
|
|
266199
|
+
function scanHardcodedSecrets(files) {
|
|
266200
|
+
const concerns = [];
|
|
266201
|
+
for (const { path: path15, hcl: hcl2 } of files) {
|
|
266202
|
+
for (const hit of findHardcodedSecrets(hcl2)) {
|
|
266203
|
+
concerns.push(
|
|
266204
|
+
buildConcern({
|
|
266205
|
+
source: NATIVE_SOURCE,
|
|
266206
|
+
rule: HARDCODED_SECRET_ARGUMENT,
|
|
266207
|
+
file: path15,
|
|
266208
|
+
line: hit.line,
|
|
266209
|
+
// a credential in the repository is readable by everyone who can read
|
|
266210
|
+
// it, and stays in the history after it is edited out
|
|
266211
|
+
severity: "high",
|
|
266212
|
+
category: "security",
|
|
266213
|
+
evidence: `\`${hit.name}\` in \`${hit.holder}\` is a string literal, so the credential it holds is committed to the repository (value not quoted here)`,
|
|
266214
|
+
remediation_hint: "Rotate the credential first \u2014 it stays in the branch history after the line is changed. Then pass it in at run time: a `sensitive` variable with no default, or a read from a secret store (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager)."
|
|
266215
|
+
})
|
|
266216
|
+
);
|
|
266217
|
+
}
|
|
266218
|
+
}
|
|
266219
|
+
return concerns;
|
|
266220
|
+
}
|
|
266221
|
+
|
|
266089
266222
|
// src/mcp/roots.ts
|
|
266090
266223
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
266091
266224
|
import { join as join10 } from "node:path";
|
|
@@ -268065,6 +268198,12 @@ var NATIVE_RULE_SCANNERS = [
|
|
|
268065
268198
|
// one. See [[stateFiles]].
|
|
268066
268199
|
scan: (ctx) => scanCommittedStateFiles(ctx.cwd)
|
|
268067
268200
|
},
|
|
268201
|
+
{
|
|
268202
|
+
name: "hardcoded-secrets",
|
|
268203
|
+
rules: [HARDCODED_SECRET_ARGUMENT],
|
|
268204
|
+
// Per file: the argument's name and its literal are both on the line itself.
|
|
268205
|
+
scan: (ctx) => ({ concerns: scanHardcodedSecrets(ctx.files) })
|
|
268206
|
+
},
|
|
268068
268207
|
{
|
|
268069
268208
|
name: "write-only",
|
|
268070
268209
|
rules: [SECRET_PERSISTED_TO_STATE],
|
|
@@ -268655,8 +268794,8 @@ function matchRoot(file2, keys, roots) {
|
|
|
268655
268794
|
const dir = dirOf2(file2);
|
|
268656
268795
|
const inside = candidates.filter((r) => r.dir !== "" && isWithin(dir, r.dir)).sort((a, b) => b.dir.length - a.dir.length);
|
|
268657
268796
|
if (inside[0]) return { root: inside[0].dir };
|
|
268658
|
-
const
|
|
268659
|
-
const scored = candidates.map((r) => ({ dir: r.dir, score: tokens(r.dir).filter((t) =>
|
|
268797
|
+
const words2 = new Set(tokens(file2));
|
|
268798
|
+
const scored = candidates.map((r) => ({ dir: r.dir, score: tokens(r.dir).filter((t) => words2.has(t)).length })).sort((a, b) => b.score - a.score);
|
|
268660
268799
|
if (scored[0] && scored[0].score > 0 && scored[0].score !== scored[1]?.score) {
|
|
268661
268800
|
return { root: scored[0].dir };
|
|
268662
268801
|
}
|
|
@@ -272786,7 +272925,7 @@ function TerraformChangeSummaryTool(ctx) {
|
|
|
272786
272925
|
// src/mcp/checkout.ts
|
|
272787
272926
|
import { createHash as createHash9 } from "node:crypto";
|
|
272788
272927
|
import { statSync as statSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
272789
|
-
import { join as
|
|
272928
|
+
import { join as join36 } from "node:path";
|
|
272790
272929
|
|
|
272791
272930
|
// node_modules/.pnpm/@infraweaver-io+ci@0.1.8/node_modules/@infraweaver-io/ci/dist/diffCoverage.js
|
|
272792
272931
|
import { isAbsolute as isAbsolute3, normalize as normalize3, resolve as resolve5 } from "node:path";
|
|
@@ -274140,7 +274279,11 @@ function isRemediationBranch(branch) {
|
|
|
274140
274279
|
return REMEDIATION_BRANCH.test(branch);
|
|
274141
274280
|
}
|
|
274142
274281
|
function groupIdFromBranch(branch) {
|
|
274143
|
-
return branch.match(/^remediate\/(
|
|
274282
|
+
return branch.match(/^remediate\/(.+?)(?:--.+)?$/)?.[1] ?? null;
|
|
274283
|
+
}
|
|
274284
|
+
function remediationBranchSuffix(base, defaultBranch) {
|
|
274285
|
+
if (!base || !defaultBranch || base === defaultBranch) return "";
|
|
274286
|
+
return `--${base.replace(/[^A-Za-z0-9._-]+/g, "-")}`;
|
|
274144
274287
|
}
|
|
274145
274288
|
function matchesBotIdentity(identity) {
|
|
274146
274289
|
const normalized = identity.replace(/\[bot\]$/i, "").toLowerCase();
|
|
@@ -276493,6 +276636,8 @@ This mode standardises STRUCTURE while preserving BEHAVIOUR \u2014 the equivalen
|
|
|
276493
276636
|
- \`${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.
|
|
276494
276637
|
- \`${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.
|
|
276495
276638
|
|
|
276639
|
+
**A result marked \`report_only\` is an observation, not work.** The repository is a module other configurations call (\`report_only_reason\` says why), and restructuring it 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
|
+
|
|
276496
276641
|
**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.
|
|
276497
276642
|
|
|
276498
276643
|
Pick the highest-value refactor across ALL THREE detectors. Only when they ALL come back empty \u2014 or all that remains is a cluster in a near-group root \u2014 is there genuinely nothing to do: call \`${t("report_progress")}\` with an ACCURATE message \u2014 e.g. "No behaviour-preserving refactor found: no extraction clusters and no idiomatic-normalisation candidates." \u2014 and **stop**. Two anti-patterns to avoid in that message: (i) never call a repo "already idiomatic" while normalisation candidates remain; (ii) when what's left is behaviour-CHANGING modernisation \u2014 a deprecated-resource swap (\`aws_launch_configuration\`\u2192\`aws_launch_template\`, \`aws_elb\`\u2192\`aws_lb\`, \`template_file\`\u2192\`templatefile()\`) \u2014 do NOT report "nothing to refactor": that is real work, but it ALTERS the resource set, so it belongs to Remediate. Say so explicitly rather than implying the code is clean.
|
|
@@ -276579,7 +276724,7 @@ This mode keeps already-open ${PRODUCT_NAME} remediation PRs healthy. A remediat
|
|
|
276579
276724
|
- **resolved-on-base? \u2192 close it**: look for a group in step 3's scan whose \`id\` equals the PR's \`group_id\` (for a by-rule/batch PR, match on the concern ids it covered). If **no** current group/concern corresponds, the concern was already fixed on the base (a human fix, or a base change removed the file) \u2014 the PR is redundant. Call \`${t("close_pull_request")}\` with a one-line \`comment\` explaining it's resolved on the base. Do not push anything for this PR.
|
|
276580
276725
|
- **still present \u2192 re-derive the fix on the current base**:
|
|
276581
276726
|
- **read WHY the CI failed, before changing anything** (\`checks_failing\` PRs only): when step 2 gave the PR a \`failing_check_suite_id\`, call \`${t("get_check_suite_logs")}\` with that id FIRST. Re-deriving without reading the failure is exactly how attempt 2 and attempt 3 become identical repeats of attempt 1 \u2014 same fix, same red check, three times, until the retry cap escalates a PR nobody learned anything about. Use the returned \`failed_steps\` and log excerpt to decide what to do DIFFERENTLY this attempt. If the log shows the failure is not ours \u2014 a broken base, a missing credential, an unrelated flaky job \u2014 do not spend an attempt re-deriving: add \`needs-human\` (\`${t("add_labels")}\`), post ONE comment naming the failing step, and move on. Record the cause in the PR body/comment you write below, so the next attempt and any human start from what you found. When the id is absent, or the tool reports no failed runs, say so in the comment and continue with the plain re-derive rather than guessing.
|
|
276582
|
-
- **branch**: recreate the remediation branch at the current base HEAD via \`${t("git")}\` (\`git checkout -B
|
|
276727
|
+
- **branch**: recreate the remediation branch at the current base HEAD via \`${t("git")}\` (\`git({ command: "checkout", args: ["-B", <the PR's branch>] })\`, the \`branch\` step 2 returned) \u2014 \`-B\` force-resets it to the just-scanned base so the diff is only your fix.
|
|
276583
276728
|
- **fix \u2192 validate \u2192 plan \u2192 keep tests consistent \u2192 prove it**: apply the minimal fix for that group exactly as in **Remediate** step 4 (same \`${t("terraform_validate")}\`, \`${t("terraform_plan")}\`, \`${t("terraform_module_tests")}\`, and \`${t("terraform_verify_remediation")}\` gates, and the same guardrails \u2014 never open/keep a PR whose validate didn't pass, abandon a group that would destroy a stateful resource, etc.).
|
|
276584
276729
|
- **force-update the PR branch**: \`${t("push_branch")}\` with \`force: true\` (the PR already exists; force-updating its branch refreshes it in place \u2014 do NOT open a second PR). The Terraform-only / secret / destroy guardrails still run at push time.
|
|
276585
276730
|
- **refresh the body**: \`${t("update_pull_request_body")}\` rebuilt from the fresh \`${t("terraform_verify_remediation")}\` result (the Remediation PR format below), and add a one-line note that it was rebased onto the current base (\`<short-sha>\`) on this run.
|
|
@@ -276624,8 +276769,8 @@ function remediateMode(t) {
|
|
|
276624
276769
|
|
|
276625
276770
|
4. **for the chosen group**:
|
|
276626
276771
|
- **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.
|
|
276627
|
-
- **idempotency**: the remediation branch is \`remediate/<group-id
|
|
276628
|
-
- **branch**: create
|
|
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.
|
|
276773
|
+
- **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.
|
|
276629
276774
|
- **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.
|
|
276630
276775
|
- **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.
|
|
276631
276776
|
- **reuse a proven fix (optional, do this BEFORE editing)**: call \`${t("terraform_fix_memory")}\`. When proven-fix memory is enabled it returns any patterns whose \`finding_type\` matches this group's concerns \u2014 each a transformation that already passed a \`\u2717\u2192\u2713\` proof on this repo or elsewhere in the fleet, with its \`remediation_hint\` + a \`before_example\`. Use a matching pattern as your STARTING POINT (it saves you rediscovering the approach), but ADAPT it to this repo's own resources \u2014 it is a prior, never a patch to paste. You MUST still run \`${t("terraform_verify_remediation")}\` to prove \`\u2717\u2192\u2713\` here; a pattern is never blind-applied and never substitutes for the per-target proof. Returns an empty list (never an error) when memory is off or nothing matches \u2014 then fix from first principles as usual.
|
|
@@ -276685,7 +276830,7 @@ This mode composes the **Remediate** and **Refactor** verbs into a single run. I
|
|
|
276685
276830
|
- **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.
|
|
276686
276831
|
|
|
276687
276832
|
3. **REFACTOR (phase 2) \u2014 modularise on top of the committed fix**: follow the **Refactor** mode's flow:
|
|
276688
|
-
- \`${t("module_extraction_candidates")}\` / \`${t("terraform_normalization_candidates")}\` \u2192 pick one behaviour-preserving refactor. 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\`).
|
|
276833
|
+
- \`${t("module_extraction_candidates")}\` / \`${t("terraform_normalization_candidates")}\` \u2192 pick one behaviour-preserving refactor; a result marked \`report_only\` (the repository is 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\`).
|
|
276689
276834
|
- 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")}\`).
|
|
276690
276835
|
- \`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.
|
|
276691
276836
|
- **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.
|
|
@@ -277251,7 +277396,7 @@ async function ensurePackageManager(params) {
|
|
|
277251
277396
|
// src/mcp/shell.ts
|
|
277252
277397
|
var ShellParams = type({
|
|
277253
277398
|
command: "string",
|
|
277254
|
-
description: "string",
|
|
277399
|
+
"description?": "string",
|
|
277255
277400
|
"timeout?": type.number.describe(
|
|
277256
277401
|
"Timeout in MILLISECONDS (not seconds). Default 30000 (30s), max 120000 (2m). e.g. timeout: 180000 for 3 minutes; timeout: 180 means 180ms and will kill the process almost immediately."
|
|
277257
277402
|
),
|
|
@@ -277486,7 +277631,7 @@ function ShellTool(ctx) {
|
|
|
277486
277631
|
return tool({
|
|
277487
277632
|
name: "shell",
|
|
277488
277633
|
timeoutMs: 12e4,
|
|
277489
|
-
description: `Execute shell commands securely. Environment is filtered to remove API keys and secrets.
|
|
277634
|
+
description: `Execute shell commands securely. Environment is filtered to remove API keys and secrets. NOT for git: any command running \`git\` is refused here \u2014 use the git tool (and push_branch / git_fetch).
|
|
277490
277635
|
|
|
277491
277636
|
Example: \`shell({ command: "pnpm test", description: "run the test suite" })\`.
|
|
277492
277637
|
|
|
@@ -278232,18 +278377,35 @@ function spillGitOutput(params) {
|
|
|
278232
278377
|
};
|
|
278233
278378
|
}
|
|
278234
278379
|
var subcommandPattern = regex("^[a-z][a-z0-9-]*$");
|
|
278380
|
+
var commandLinePattern = regex("^git\\s+[a-z][a-z0-9-]*(?:\\s.*)?$");
|
|
278235
278381
|
var Git = type({
|
|
278236
|
-
command: type(subcommandPattern).describe("Git command (e.g., 'status', 'log', 'diff')"),
|
|
278382
|
+
command: type(subcommandPattern).or(type(commandLinePattern)).describe("Git command (e.g., 'status', 'log', 'diff')").optional(),
|
|
278237
278383
|
args: type.string.array().describe("Additional arguments for the git command").optional()
|
|
278238
278384
|
});
|
|
278385
|
+
function splitWords(line) {
|
|
278386
|
+
return [...line.matchAll(/"([^"]*)"|'([^']*)'|(\S+)/g)].map((m) => m[1] ?? m[2] ?? m[3] ?? "");
|
|
278387
|
+
}
|
|
278388
|
+
function normalizeGitCall(params) {
|
|
278389
|
+
let words2;
|
|
278390
|
+
if (params.command === void 0) words2 = [...params.args ?? []];
|
|
278391
|
+
else if (/^git\s/.test(params.command))
|
|
278392
|
+
words2 = [...splitWords(params.command).slice(1), ...params.args ?? []];
|
|
278393
|
+
else return { command: params.command, args: params.args ?? [] };
|
|
278394
|
+
const [command, ...args2] = words2[0] === "git" ? words2.slice(1) : words2;
|
|
278395
|
+
if (command === void 0 || !/^[a-z][a-z0-9-]*$/.test(command)) {
|
|
278396
|
+
throw new Error(
|
|
278397
|
+
`command must be a Git subcommand such as 'status' or 'checkout' (was "${command ?? ""}")`
|
|
278398
|
+
);
|
|
278399
|
+
}
|
|
278400
|
+
return { command, args: args2 };
|
|
278401
|
+
}
|
|
278239
278402
|
function GitTool(ctx) {
|
|
278240
278403
|
return tool({
|
|
278241
278404
|
name: "git",
|
|
278242
278405
|
description: 'Run a git subcommand. `command` is the subcommand ONLY \u2014 never repeat it inside `args`. `args` is optional; omit it entirely for no-flag invocations like plain `git status`. Example: `git({ command: "status" })` for plain `git status`. Example: `git({ command: "log", args: ["--oneline", "-n", "20"] })`. Example: `git({ command: "diff", args: ["--merge-base", "origin/main"] })` \u2014 merge-base diff including uncommitted edits (single MCP call). Example: `git({ command: "diff", args: ["origin/main...HEAD"] })` \u2014 three-dot, committed-only changes vs merge-base. For PR-scope diffs ALWAYS use `--merge-base <base>` or three-dot `<base>...HEAD`. Bare `<base>` and two-dot `<base>..HEAD` are symmetric (working-tree-or-HEAD vs ref): when your branch is behind `<base>` they include the inverse of every commit on `<base>` you lack \u2014 pure noise, and this tool will reject those forms when the divergence is detected. Output >50K chars is spilled to a tmp file; the tool returns a head preview + path you can `read` selectively. For push/fetch, use the dedicated MCP tools (push_branch, git_fetch). git pull is not available \u2014 use git_fetch then this tool with command \'merge\'.',
|
|
278243
278406
|
parameters: Git,
|
|
278244
278407
|
execute: execute(async (params) => {
|
|
278245
|
-
const command = params
|
|
278246
|
-
const args2 = params.args ?? [];
|
|
278408
|
+
const { command, args: args2 } = normalizeGitCall(params);
|
|
278247
278409
|
if (args2[0]?.toLowerCase() === command.toLowerCase()) {
|
|
278248
278410
|
throw new Error(
|
|
278249
278411
|
`git ${command}: '${args2[0]}' duplicates the subcommand \u2014 drop args[0] (the subcommand only belongs in 'command'). git would otherwise parse it as a pathspec and silently return empty/clean output when nothing matches. if you really meant a pathspec named '${args2[0]}', use args: ["--", "${args2[0]}"].`
|
|
@@ -278415,7 +278577,7 @@ function PushTagsTool(ctx) {
|
|
|
278415
278577
|
}
|
|
278416
278578
|
|
|
278417
278579
|
// src/mcp/review.ts
|
|
278418
|
-
import { readFileSync as
|
|
278580
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
278419
278581
|
|
|
278420
278582
|
// src/mcp/findingAudit.ts
|
|
278421
278583
|
var COHERENCE_RULES = {
|
|
@@ -279431,6 +279593,7 @@ var Inputs = type({
|
|
|
279431
279593
|
// org-repo | author | third-party). Structured scope, not prompt text — see
|
|
279432
279594
|
// parseRefactorSource / withRefactorSource. Gates the behaviour-altering b.4.
|
|
279433
279595
|
"refactor_source?": type.string.or("undefined"),
|
|
279596
|
+
"refactor_examples?": type.string.or("undefined"),
|
|
279434
279597
|
"review_instructions?": type.string.or("undefined"),
|
|
279435
279598
|
"fp_filtering_instructions?": type.string.or("undefined"),
|
|
279436
279599
|
"remediation_instructions?": type.string.or("undefined"),
|
|
@@ -279508,6 +279671,7 @@ function resolveNonPromptInputs() {
|
|
|
279508
279671
|
registry_token: getInput("registry_token") || void 0,
|
|
279509
279672
|
registry_host: getInput("registry_host") || void 0,
|
|
279510
279673
|
refactor_source: getInput("refactor_source") || void 0,
|
|
279674
|
+
refactor_examples: getInput("refactor_examples") || void 0,
|
|
279511
279675
|
review_instructions: getInput("review_instructions") || void 0,
|
|
279512
279676
|
fp_filtering_instructions: getInput("fp_filtering_instructions") || void 0,
|
|
279513
279677
|
remediation_instructions: getInput("remediation_instructions") || void 0,
|
|
@@ -279809,6 +279973,8 @@ function resolvePayload(resolvedPromptInput, repoSettings, orgRequiredControls =
|
|
|
279809
279973
|
// Refactor mode for the b.4 consent gate. undefined → auto. Action-input/
|
|
279810
279974
|
// trusted-dispatch only (not the untrusted repo file).
|
|
279811
279975
|
refactorSource,
|
|
279976
|
+
// opt in to refactoring `examples/` roots, which Refactor leaves alone by default
|
|
279977
|
+
refactorExamples: parseBooleanInput(inputs.refactor_examples),
|
|
279812
279978
|
// a `@infraweaver fix …` command parsed from the triggering comment
|
|
279813
279979
|
// body (the raw prompt), scoping the run to a specific concern/severity/file.
|
|
279814
279980
|
// null when the prompt isn't a recognised command.
|
|
@@ -281623,7 +281789,7 @@ function apply(worktree, path15, cs) {
|
|
|
281623
281789
|
|
|
281624
281790
|
// src/mcp/terraform/gateScan.ts
|
|
281625
281791
|
import { existsSync as existsSync7, mkdtempSync as mkdtempSync3, rmSync as rmSync6 } from "node:fs";
|
|
281626
|
-
import { join as
|
|
281792
|
+
import { join as join33, posix as posix10 } from "node:path";
|
|
281627
281793
|
|
|
281628
281794
|
// src/mcp/terraform/coverage.ts
|
|
281629
281795
|
function bandOf(group2, concerns, signals) {
|
|
@@ -282061,6 +282227,66 @@ function dedupeCrossScanner(concerns) {
|
|
|
282061
282227
|
return [...merged, ...passthrough];
|
|
282062
282228
|
}
|
|
282063
282229
|
|
|
282230
|
+
// src/mcp/terraform/verifySites.ts
|
|
282231
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
282232
|
+
import { join as join29 } from "node:path";
|
|
282233
|
+
function fileReader(cwd) {
|
|
282234
|
+
const cache3 = /* @__PURE__ */ new Map();
|
|
282235
|
+
return (file2) => {
|
|
282236
|
+
if (!cache3.has(file2)) {
|
|
282237
|
+
let text;
|
|
282238
|
+
try {
|
|
282239
|
+
text = readFileSync17(join29(cwd, file2), "utf8");
|
|
282240
|
+
} catch {
|
|
282241
|
+
text = null;
|
|
282242
|
+
}
|
|
282243
|
+
cache3.set(file2, text);
|
|
282244
|
+
}
|
|
282245
|
+
return cache3.get(file2) ?? null;
|
|
282246
|
+
};
|
|
282247
|
+
}
|
|
282248
|
+
function siteOf(c, read3) {
|
|
282249
|
+
const text = read3(c.location.file);
|
|
282250
|
+
return text === null ? null : resourceAddressAt(text, c.location.line);
|
|
282251
|
+
}
|
|
282252
|
+
function recordConcernSites(session, concerns, cwd) {
|
|
282253
|
+
const read3 = fileReader(cwd);
|
|
282254
|
+
session.siteById ??= /* @__PURE__ */ new Map();
|
|
282255
|
+
session.firstSitesByKey ??= /* @__PURE__ */ new Map();
|
|
282256
|
+
const first = session.firstSitesByKey;
|
|
282257
|
+
const fresh = /* @__PURE__ */ new Map();
|
|
282258
|
+
for (const c of concerns) {
|
|
282259
|
+
const site = siteOf(c, read3);
|
|
282260
|
+
session.siteById.set(c.id, site);
|
|
282261
|
+
const key = concernKeyOf(c);
|
|
282262
|
+
if (first.has(key)) continue;
|
|
282263
|
+
const sites = fresh.get(key) ?? /* @__PURE__ */ new Set();
|
|
282264
|
+
sites.add(site);
|
|
282265
|
+
fresh.set(key, sites);
|
|
282266
|
+
}
|
|
282267
|
+
for (const [key, sites] of fresh) first.set(key, sites);
|
|
282268
|
+
}
|
|
282269
|
+
function resolvedAtSite(params) {
|
|
282270
|
+
const firingByKey = /* @__PURE__ */ new Map();
|
|
282271
|
+
for (const c of params.current) {
|
|
282272
|
+
const list = firingByKey.get(c.key) ?? [];
|
|
282273
|
+
list.push(c.site);
|
|
282274
|
+
firingByKey.set(c.key, list);
|
|
282275
|
+
}
|
|
282276
|
+
const out = [];
|
|
282277
|
+
for (const r of params.requested) {
|
|
282278
|
+
if (r.site === null || r.file === void 0) continue;
|
|
282279
|
+
const firing = firingByKey.get(r.key) ?? [];
|
|
282280
|
+
const known = params.firstSites.get(r.key);
|
|
282281
|
+
if (known === void 0) continue;
|
|
282282
|
+
if (firing.some((s) => s === null || !known.has(s))) continue;
|
|
282283
|
+
if (firing.includes(r.site)) continue;
|
|
282284
|
+
if (!params.declared(r.file).has(r.site)) continue;
|
|
282285
|
+
out.push(r.id);
|
|
282286
|
+
}
|
|
282287
|
+
return out;
|
|
282288
|
+
}
|
|
282289
|
+
|
|
282064
282290
|
// src/mcp/terraform/concernResult.ts
|
|
282065
282291
|
function annotateConcerns(rawConcerns, opts) {
|
|
282066
282292
|
const inScope = opts.inScope ?? (() => true);
|
|
@@ -282069,6 +282295,10 @@ function annotateConcerns(rawConcerns, opts) {
|
|
|
282069
282295
|
opts.cwd
|
|
282070
282296
|
);
|
|
282071
282297
|
}
|
|
282298
|
+
function remediationBaseOf(ctx) {
|
|
282299
|
+
const head = ctx.toolState.initialHead;
|
|
282300
|
+
return ctx.payload.baseBranch?.trim() || (head?.kind === "branch" ? head.name : void 0) || ctx.repo?.data.default_branch?.trim() || void 0;
|
|
282301
|
+
}
|
|
282072
282302
|
function buildConcernResult(ctx, rawConcerns, opts) {
|
|
282073
282303
|
const fullBaseline = dedupe(rawConcerns);
|
|
282074
282304
|
const session = scanSessionOf(ctx.toolState);
|
|
@@ -282083,6 +282313,7 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282083
282313
|
fullBaseline.map((c) => concernKeyOf(c))
|
|
282084
282314
|
);
|
|
282085
282315
|
recordConcernKeys(session, fullBaseline);
|
|
282316
|
+
recordConcernSites(session, fullBaseline, opts.cwd);
|
|
282086
282317
|
session.baselineFmtDriftFiles = union3(
|
|
282087
282318
|
session.baselineFmtDriftFiles,
|
|
282088
282319
|
fullBaseline.filter((c) => c.source === "terraform-fmt").map((c) => c.location.file)
|
|
@@ -282097,8 +282328,13 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282097
282328
|
active,
|
|
282098
282329
|
opts.autonomyThreshold
|
|
282099
282330
|
);
|
|
282100
|
-
const
|
|
282101
|
-
|
|
282331
|
+
const suffix2 = remediationBranchSuffix(
|
|
282332
|
+
remediationBaseOf(ctx),
|
|
282333
|
+
ctx.repo?.data.default_branch?.trim() || void 0
|
|
282334
|
+
);
|
|
282335
|
+
const groups2 = (opts.priority ? prioritizeGroups(annotatedGroups, active, opts.priority) : annotatedGroups).map((g) => ({ ...g, branch: `remediate/${g.id}${suffix2}` }));
|
|
282336
|
+
const planned = planBatches(groups2);
|
|
282337
|
+
const batchPlan = planned.batch_branch ? { ...planned, batch_branch: `${planned.batch_branch}${suffix2}` } : planned;
|
|
282102
282338
|
const bySeverity = {};
|
|
282103
282339
|
for (const c of active) bySeverity[c.severity] = (bySeverity[c.severity] ?? 0) + 1;
|
|
282104
282340
|
return {
|
|
@@ -282114,7 +282350,7 @@ function buildConcernResult(ctx, rawConcerns, opts) {
|
|
|
282114
282350
|
|
|
282115
282351
|
// src/mcp/terraform/initArtefacts.ts
|
|
282116
282352
|
import { rmSync as rmSync4 } from "node:fs";
|
|
282117
|
-
import { join as
|
|
282353
|
+
import { join as join30, posix as posix9 } from "node:path";
|
|
282118
282354
|
var INIT_ARTEFACTS = /* @__PURE__ */ new Set([".terraform", ".terraform.lock.hcl"]);
|
|
282119
282355
|
function initArtefacts(cwd) {
|
|
282120
282356
|
const r = run("git", ["status", "--porcelain=v1", "-z", "--untracked-files=normal"], cwd);
|
|
@@ -282137,7 +282373,7 @@ function removeNewInitArtefacts(cwd, before, by) {
|
|
|
282137
282373
|
const created = [...after?.untracked ?? []].filter((p) => !before.untracked.has(p));
|
|
282138
282374
|
const changed = [...after?.modifiedLocks ?? []].filter((p) => !before.modifiedLocks.has(p));
|
|
282139
282375
|
if (!top || created.length + changed.length === 0) return;
|
|
282140
|
-
for (const p of created) rmSync4(
|
|
282376
|
+
for (const p of created) rmSync4(join30(top, p), { recursive: true, force: true });
|
|
282141
282377
|
if (changed.length > 0) run("git", ["checkout", "--", ...changed], top);
|
|
282142
282378
|
resetTerraformInitCache();
|
|
282143
282379
|
log2.info(
|
|
@@ -282146,8 +282382,8 @@ function removeNewInitArtefacts(cwd, before, by) {
|
|
|
282146
282382
|
}
|
|
282147
282383
|
|
|
282148
282384
|
// src/mcp/terraform/secretScan.ts
|
|
282149
|
-
import { readFileSync as
|
|
282150
|
-
import { join as
|
|
282385
|
+
import { readFileSync as readFileSync18, rmSync as rmSync5 } from "node:fs";
|
|
282386
|
+
import { join as join31 } from "node:path";
|
|
282151
282387
|
function parseBetterleaksReport(json5, prefix2 = "") {
|
|
282152
282388
|
const doc = JSON.parse(json5);
|
|
282153
282389
|
if (Array.isArray(doc) || !doc || typeof doc !== "object" || !("findings" in doc)) {
|
|
@@ -282181,7 +282417,7 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282181
282417
|
const top = run("git", ["rev-parse", "--show-toplevel"], cwd).stdout.trim();
|
|
282182
282418
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd).stdout.trim();
|
|
282183
282419
|
if (!top) return { ran: false, reason: "not a git checkout", concerns: [] };
|
|
282184
|
-
const report2 =
|
|
282420
|
+
const report2 = join31(tmp, `betterleaks-${process.pid}.json`);
|
|
282185
282421
|
try {
|
|
282186
282422
|
const r = await runAsync(
|
|
282187
282423
|
"betterleaks",
|
|
@@ -282204,7 +282440,7 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282204
282440
|
const why = (r.stderr || r.stdout).trim().split("\n").pop() ?? "";
|
|
282205
282441
|
let parsed2;
|
|
282206
282442
|
try {
|
|
282207
|
-
parsed2 = parseBetterleaksReport(
|
|
282443
|
+
parsed2 = parseBetterleaksReport(readFileSync18(report2, "utf-8"), prefix2);
|
|
282208
282444
|
} catch (error63) {
|
|
282209
282445
|
const reason = r.status !== 0 ? `betterleaks exited ${r.status}: ${why}` : `${error63}`;
|
|
282210
282446
|
return { ran: false, reason, concerns: [] };
|
|
@@ -282219,8 +282455,8 @@ async function scanAddedSecrets(cwd, mergeBase, tmp) {
|
|
|
282219
282455
|
}
|
|
282220
282456
|
|
|
282221
282457
|
// src/mcp/terraform/tools/scan.ts
|
|
282222
|
-
import { readFileSync as
|
|
282223
|
-
import { join as
|
|
282458
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
282459
|
+
import { join as join32 } from "node:path";
|
|
282224
282460
|
|
|
282225
282461
|
// src/mcp/terraform/noiseProfile.ts
|
|
282226
282462
|
var MIN_DISMISSAL_REPOS = 3;
|
|
@@ -282406,7 +282642,7 @@ async function runScan(ctx, {
|
|
|
282406
282642
|
outcomes.flatMap((o) => o.concerns),
|
|
282407
282643
|
(rel) => {
|
|
282408
282644
|
try {
|
|
282409
|
-
return
|
|
282645
|
+
return readFileSync19(join32(cwd, rel), "utf-8");
|
|
282410
282646
|
} catch {
|
|
282411
282647
|
return null;
|
|
282412
282648
|
}
|
|
@@ -282558,8 +282794,8 @@ function checkOutBase(cwd, pr, tmp) {
|
|
|
282558
282794
|
}
|
|
282559
282795
|
const mergeBase = run("git", ["merge-base", pr.baseSha, "HEAD"], cwd).stdout.trim() || pr.baseSha;
|
|
282560
282796
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd).stdout.trim();
|
|
282561
|
-
const parent = mkdtempSync3(
|
|
282562
|
-
const worktree =
|
|
282797
|
+
const parent = mkdtempSync3(join33(tmp, "scan-delta-base-"));
|
|
282798
|
+
const worktree = join33(parent, "wt");
|
|
282563
282799
|
if (run("git", ["worktree", "add", "--detach", worktree, mergeBase], cwd).status !== 0) {
|
|
282564
282800
|
rmSync6(parent, { recursive: true, force: true });
|
|
282565
282801
|
log2.warning("\xBB scan delta: could not check out the base \u2014 every finding is treated as new.");
|
|
@@ -282567,7 +282803,7 @@ function checkOutBase(cwd, pr, tmp) {
|
|
|
282567
282803
|
}
|
|
282568
282804
|
return {
|
|
282569
282805
|
mergeBase,
|
|
282570
|
-
cwd: prefix2 ?
|
|
282806
|
+
cwd: prefix2 ? join33(worktree, prefix2) : worktree,
|
|
282571
282807
|
close: () => {
|
|
282572
282808
|
run("git", ["worktree", "remove", "--force", worktree], cwd);
|
|
282573
282809
|
rmSync6(parent, { recursive: true, force: true });
|
|
@@ -283502,7 +283738,7 @@ ${coverageState.lastBreakdown}`
|
|
|
283502
283738
|
}
|
|
283503
283739
|
function readReviewedFile(path15) {
|
|
283504
283740
|
try {
|
|
283505
|
-
return
|
|
283741
|
+
return readFileSync20(resolveWithinCwd(resolveRepoRoot(), path15), "utf-8");
|
|
283506
283742
|
} catch {
|
|
283507
283743
|
return null;
|
|
283508
283744
|
}
|
|
@@ -283817,7 +284053,7 @@ function fastForwardDiff(params, exec2) {
|
|
|
283817
284053
|
|
|
283818
284054
|
// src/utils/prompt/changeImpact.ts
|
|
283819
284055
|
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
283820
|
-
import { join as
|
|
284056
|
+
import { join as join34 } from "node:path";
|
|
283821
284057
|
var MAX_ATOMS = 20;
|
|
283822
284058
|
var MAX_REFS_PER_ATOM = 6;
|
|
283823
284059
|
var MAX_EXCERPT = 160;
|
|
@@ -283997,7 +284233,7 @@ function createChangeImpactArtifact(params) {
|
|
|
283997
284233
|
fileCount: params.files.length,
|
|
283998
284234
|
lookupError
|
|
283999
284235
|
});
|
|
284000
|
-
const path15 =
|
|
284236
|
+
const path15 = join34(
|
|
284001
284237
|
params.tmpdir,
|
|
284002
284238
|
`pr-${params.pullNumber}-${params.headSha.slice(0, 7)}-impact.md`
|
|
284003
284239
|
);
|
|
@@ -284017,7 +284253,7 @@ function createChangeImpactArtifact(params) {
|
|
|
284017
284253
|
import { execFileSync, execSync as execSync2 } from "node:child_process";
|
|
284018
284254
|
import { mkdtempSync as mkdtempSync4, readdirSync as readdirSync5, realpathSync as realpathSync4, unlinkSync as unlinkSync2 } from "node:fs";
|
|
284019
284255
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
284020
|
-
import { join as
|
|
284256
|
+
import { join as join35 } from "node:path";
|
|
284021
284257
|
|
|
284022
284258
|
// src/utils/github/ghaCore.ts
|
|
284023
284259
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
@@ -284040,7 +284276,7 @@ var TEMP_DIR_STATE_KEY = "infraweaver_temp_dir";
|
|
|
284040
284276
|
|
|
284041
284277
|
// src/utils/setup/setup.ts
|
|
284042
284278
|
function createTempDirectory() {
|
|
284043
|
-
const sharedTempDir = mkdtempSync4(
|
|
284279
|
+
const sharedTempDir = mkdtempSync4(join35(tmpdir2(), `${PRODUCT_SLUG}-`));
|
|
284044
284280
|
process.env.INFRAWEAVER_TEMP_DIR = sharedTempDir;
|
|
284045
284281
|
saveState2(TEMP_DIR_STATE_KEY, sharedTempDir);
|
|
284046
284282
|
log2.info(`\xBB created temp dir at ${sharedTempDir}`);
|
|
@@ -284086,13 +284322,13 @@ function wipeRunnerLeakSurface() {
|
|
|
284086
284322
|
return [];
|
|
284087
284323
|
}
|
|
284088
284324
|
};
|
|
284089
|
-
const fileCommandsDir =
|
|
284325
|
+
const fileCommandsDir = join35(runnerTemp, "_runner_file_commands");
|
|
284090
284326
|
for (const entry4 of listDir(fileCommandsDir)) {
|
|
284091
|
-
tryUnlink(
|
|
284327
|
+
tryUnlink(join35(fileCommandsDir, entry4));
|
|
284092
284328
|
}
|
|
284093
284329
|
for (const entry4 of listDir(runnerTemp)) {
|
|
284094
284330
|
if (entry4.endsWith(".sh") || /^git-credentials-.*\.config$/.test(entry4)) {
|
|
284095
|
-
tryUnlink(
|
|
284331
|
+
tryUnlink(join35(runnerTemp, entry4));
|
|
284096
284332
|
}
|
|
284097
284333
|
}
|
|
284098
284334
|
if (wiped.length > 0) {
|
|
@@ -284591,7 +284827,7 @@ function CheckoutPrTool(ctx) {
|
|
|
284591
284827
|
headSha: ctx.toolState.checkoutSha
|
|
284592
284828
|
});
|
|
284593
284829
|
if (incremental) {
|
|
284594
|
-
incrementalDiffPath =
|
|
284830
|
+
incrementalDiffPath = join36(
|
|
284595
284831
|
tempDir,
|
|
284596
284832
|
`pr-${pull_number}-${beforeShort}-${headShort}-incremental.diff`
|
|
284597
284833
|
);
|
|
@@ -284605,7 +284841,7 @@ function CheckoutPrTool(ctx) {
|
|
|
284605
284841
|
const diffPreview = formatResult.content.split("\n").slice(0, 100).join("\n");
|
|
284606
284842
|
log2.debug(`formatted diff preview (first 100 lines):
|
|
284607
284843
|
${diffPreview}`);
|
|
284608
|
-
const diffPath =
|
|
284844
|
+
const diffPath = join36(tempDir, `pr-${pull_number}-${headShort}.diff`);
|
|
284609
284845
|
writeFileSync10(diffPath, formatResult.content);
|
|
284610
284846
|
log2.debug(`wrote diff to ${diffPath} (${formatResult.content.length} bytes)`);
|
|
284611
284847
|
ctx.toolState.diffCoverage = createDiffCoverageState({
|
|
@@ -284746,7 +284982,7 @@ ${dirty}`
|
|
|
284746
284982
|
|
|
284747
284983
|
// src/mcp/checkSuite.ts
|
|
284748
284984
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync11 } from "node:fs";
|
|
284749
|
-
import { join as
|
|
284985
|
+
import { join as join37 } from "node:path";
|
|
284750
284986
|
import { stripVTControlCharacters } from "node:util";
|
|
284751
284987
|
var GetCheckSuiteLogs = type({
|
|
284752
284988
|
check_suite_id: type.number.describe("the id from check_suite.id")
|
|
@@ -284841,7 +285077,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
284841
285077
|
};
|
|
284842
285078
|
}
|
|
284843
285079
|
const tempDir = getTempDir();
|
|
284844
|
-
const logsDir =
|
|
285080
|
+
const logsDir = join37(tempDir, "ci-logs");
|
|
284845
285081
|
mkdirSync3(logsDir, { recursive: true });
|
|
284846
285082
|
const jobLists = await mapWithConcurrency(
|
|
284847
285083
|
failedRuns,
|
|
@@ -284865,7 +285101,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
284865
285101
|
request: { signal: AbortSignal.timeout(1e4) }
|
|
284866
285102
|
});
|
|
284867
285103
|
const logsText = typeof data === "string" ? data : Buffer.from(data).toString("utf8");
|
|
284868
|
-
const logPath =
|
|
285104
|
+
const logPath = join37(logsDir, `job-${job.id}.log`);
|
|
284869
285105
|
writeFileSync11(logPath, logsText);
|
|
284870
285106
|
const analysis = analyzeLog(logsText, 80);
|
|
284871
285107
|
const failedSteps = job.steps?.filter((s) => s.conclusion === "failure").map((s) => `Step ${s.number}: ${s.name}`) ?? [];
|
|
@@ -284927,7 +285163,7 @@ function GetCheckSuiteLogsTool(ctx) {
|
|
|
284927
285163
|
|
|
284928
285164
|
// src/mcp/commitInfo.ts
|
|
284929
285165
|
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
284930
|
-
import { join as
|
|
285166
|
+
import { join as join38 } from "node:path";
|
|
284931
285167
|
var CommitInfo = type({
|
|
284932
285168
|
sha: type.string.describe("the commit SHA (full or abbreviated) to fetch")
|
|
284933
285169
|
});
|
|
@@ -284946,7 +285182,7 @@ function CommitInfoTool(ctx) {
|
|
|
284946
285182
|
const files = data.files ?? [];
|
|
284947
285183
|
const formatResult = formatFilesWithLineNumbers(files);
|
|
284948
285184
|
const tempDir = getTempDir("get_commit_info");
|
|
284949
|
-
const diffFile =
|
|
285185
|
+
const diffFile = join38(tempDir, `commit-${sha.slice(0, 7)}.diff`);
|
|
284950
285186
|
writeFileSync12(diffFile, formatResult.content);
|
|
284951
285187
|
log2.debug(`wrote commit diff to ${diffFile} (${formatResult.content.length} bytes)`);
|
|
284952
285188
|
return {
|
|
@@ -285108,7 +285344,7 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
285108
285344
|
|
|
285109
285345
|
// src/prep/installNodeDependencies.ts
|
|
285110
285346
|
import { existsSync as existsSync8 } from "node:fs";
|
|
285111
|
-
import { join as
|
|
285347
|
+
import { join as join39 } from "node:path";
|
|
285112
285348
|
|
|
285113
285349
|
// node_modules/.pnpm/package-manager-detector@1.8.0/node_modules/package-manager-detector/dist/commands.mjs
|
|
285114
285350
|
function splitRunArgs(args2, valueFlags = []) {
|
|
@@ -285494,7 +285730,7 @@ async function installFallback(name, installSpec) {
|
|
|
285494
285730
|
return result.stderr || `failed to install ${name}`;
|
|
285495
285731
|
}
|
|
285496
285732
|
if (name === "deno") {
|
|
285497
|
-
const denoPath =
|
|
285733
|
+
const denoPath = join39(process.env.HOME || "", ".deno", "bin");
|
|
285498
285734
|
process.env.PATH = `${denoPath}:${process.env.PATH}`;
|
|
285499
285735
|
}
|
|
285500
285736
|
log2.info(`\xBB installed ${name}`);
|
|
@@ -285503,7 +285739,7 @@ async function installFallback(name, installSpec) {
|
|
|
285503
285739
|
var installNodeDependencies = {
|
|
285504
285740
|
name: "installNodeDependencies",
|
|
285505
285741
|
shouldRun: () => {
|
|
285506
|
-
const packageJsonPath =
|
|
285742
|
+
const packageJsonPath = join39(process.cwd(), "package.json");
|
|
285507
285743
|
return existsSync8(packageJsonPath);
|
|
285508
285744
|
},
|
|
285509
285745
|
run: async (options) => {
|
|
@@ -285612,8 +285848,8 @@ ${errorMessage2}`]
|
|
|
285612
285848
|
};
|
|
285613
285849
|
|
|
285614
285850
|
// src/prep/installPythonDependencies.ts
|
|
285615
|
-
import { existsSync as existsSync9, readFileSync as
|
|
285616
|
-
import { join as
|
|
285851
|
+
import { existsSync as existsSync9, readFileSync as readFileSync21 } from "node:fs";
|
|
285852
|
+
import { join as join40 } from "node:path";
|
|
285617
285853
|
var PYTHON_CONFIGS = [
|
|
285618
285854
|
{
|
|
285619
285855
|
file: "requirements.txt",
|
|
@@ -285648,7 +285884,7 @@ var PYTHON_CONFIGS = [
|
|
|
285648
285884
|
];
|
|
285649
285885
|
function pyprojectDeclaresBuildSystem(cwd) {
|
|
285650
285886
|
try {
|
|
285651
|
-
const content =
|
|
285887
|
+
const content = readFileSync21(join40(cwd, "pyproject.toml"), "utf8");
|
|
285652
285888
|
return /^\s*\[build-system\]/m.test(content);
|
|
285653
285889
|
} catch {
|
|
285654
285890
|
return false;
|
|
@@ -285698,13 +285934,13 @@ var installPythonDependencies = {
|
|
|
285698
285934
|
}
|
|
285699
285935
|
const cwd = process.cwd();
|
|
285700
285936
|
return PYTHON_CONFIGS.some(
|
|
285701
|
-
(config3) => existsSync9(
|
|
285937
|
+
(config3) => existsSync9(join40(cwd, config3.file)) && configApplies(config3, cwd)
|
|
285702
285938
|
);
|
|
285703
285939
|
},
|
|
285704
285940
|
run: async (options) => {
|
|
285705
285941
|
const cwd = process.cwd();
|
|
285706
285942
|
const config3 = PYTHON_CONFIGS.find(
|
|
285707
|
-
(c) => existsSync9(
|
|
285943
|
+
(c) => existsSync9(join40(cwd, c.file)) && configApplies(c, cwd)
|
|
285708
285944
|
);
|
|
285709
285945
|
if (!config3) {
|
|
285710
285946
|
return {
|
|
@@ -286225,12 +286461,12 @@ function AddLabelsTool(ctx) {
|
|
|
286225
286461
|
}
|
|
286226
286462
|
|
|
286227
286463
|
// src/mcp/moduleExtraction.ts
|
|
286228
|
-
import { readFileSync as
|
|
286229
|
-
import { join as
|
|
286464
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
286465
|
+
import { join as join43, posix as posix11 } from "node:path";
|
|
286230
286466
|
|
|
286231
286467
|
// src/mcp/terraform/partialInterface.ts
|
|
286232
|
-
import { readdirSync as readdirSync6, readFileSync as
|
|
286233
|
-
import { join as
|
|
286468
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync22 } from "node:fs";
|
|
286469
|
+
import { join as join41 } from "node:path";
|
|
286234
286470
|
function unmappedArguments(resource, moduleResources) {
|
|
286235
286471
|
const matching = moduleResources.filter((m) => m.type === resource.type);
|
|
286236
286472
|
if (matching.length === 0) return [];
|
|
@@ -286240,10 +286476,10 @@ function unmappedArguments(resource, moduleResources) {
|
|
|
286240
286476
|
function readDirHcl(cwd, dir) {
|
|
286241
286477
|
let text = "";
|
|
286242
286478
|
try {
|
|
286243
|
-
for (const f of readdirSync6(
|
|
286479
|
+
for (const f of readdirSync6(join41(cwd, dir)).sort((a, b) => a.localeCompare(b, "en"))) {
|
|
286244
286480
|
if (!f.endsWith(".tf")) continue;
|
|
286245
286481
|
try {
|
|
286246
|
-
text += `${
|
|
286482
|
+
text += `${readFileSync22(join41(cwd, dir, f), "utf8")}
|
|
286247
286483
|
`;
|
|
286248
286484
|
} catch {
|
|
286249
286485
|
}
|
|
@@ -286273,7 +286509,7 @@ function findPartialInterfaces(cwd) {
|
|
|
286273
286509
|
if (isInHouseModule(file2, graph)) continue;
|
|
286274
286510
|
let text;
|
|
286275
286511
|
try {
|
|
286276
|
-
text =
|
|
286512
|
+
text = readFileSync22(join41(cwd, file2), "utf8");
|
|
286277
286513
|
} catch {
|
|
286278
286514
|
continue;
|
|
286279
286515
|
}
|
|
@@ -286289,6 +286525,54 @@ function findPartialInterfaces(cwd) {
|
|
|
286289
286525
|
return out;
|
|
286290
286526
|
}
|
|
286291
286527
|
|
|
286528
|
+
// src/mcp/terraform/refactorScope.ts
|
|
286529
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync23, statSync as statSync6 } from "node:fs";
|
|
286530
|
+
import { join as join42 } from "node:path";
|
|
286531
|
+
function isExamplePath(path15) {
|
|
286532
|
+
return /(?:^|\/)examples?\//.test(path15.replace(/\\/g, "/"));
|
|
286533
|
+
}
|
|
286534
|
+
var PROVIDER_OR_BACKEND = /^\s*(?:provider\s+"|backend\s+")/m;
|
|
286535
|
+
function holdsTerraform(dir, depth) {
|
|
286536
|
+
let entries;
|
|
286537
|
+
try {
|
|
286538
|
+
entries = readdirSync7(dir);
|
|
286539
|
+
} catch {
|
|
286540
|
+
return false;
|
|
286541
|
+
}
|
|
286542
|
+
for (const name of entries) {
|
|
286543
|
+
const path15 = join42(dir, name);
|
|
286544
|
+
if (name.endsWith(".tf")) return true;
|
|
286545
|
+
if (depth > 0 && !name.startsWith(".") && statSync6(path15, { throwIfNoEntry: false })?.isDirectory()) {
|
|
286546
|
+
if (holdsTerraform(path15, depth - 1)) return true;
|
|
286547
|
+
}
|
|
286548
|
+
}
|
|
286549
|
+
return false;
|
|
286550
|
+
}
|
|
286551
|
+
function libraryRepoReason(cwd) {
|
|
286552
|
+
let rootFiles;
|
|
286553
|
+
try {
|
|
286554
|
+
rootFiles = readdirSync7(cwd).filter((f) => f.endsWith(".tf"));
|
|
286555
|
+
} catch {
|
|
286556
|
+
return null;
|
|
286557
|
+
}
|
|
286558
|
+
if (rootFiles.length === 0) return null;
|
|
286559
|
+
for (const f of rootFiles) {
|
|
286560
|
+
let text;
|
|
286561
|
+
try {
|
|
286562
|
+
text = readFileSync23(join42(cwd, f), "utf8");
|
|
286563
|
+
} catch {
|
|
286564
|
+
continue;
|
|
286565
|
+
}
|
|
286566
|
+
if (PROVIDER_OR_BACKEND.test(text)) return null;
|
|
286567
|
+
}
|
|
286568
|
+
const examples = ["examples", "example"].find((d) => existsSync10(join42(cwd, d)));
|
|
286569
|
+
if (examples === void 0 || !holdsTerraform(join42(cwd, examples), 2)) return null;
|
|
286570
|
+
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`;
|
|
286571
|
+
}
|
|
286572
|
+
function reportOnly(reason) {
|
|
286573
|
+
return reason === null ? {} : { report_only: true, report_only_reason: reason };
|
|
286574
|
+
}
|
|
286575
|
+
|
|
286292
286576
|
// src/mcp/moduleExtraction.ts
|
|
286293
286577
|
function parseResourceBlocks(hcl2) {
|
|
286294
286578
|
const out = [];
|
|
@@ -286577,7 +286861,7 @@ function findExtractionCandidates(cwd, rawCatalogue, orgModuleHcl) {
|
|
|
286577
286861
|
if (isInHouseModule(file2, graph) !== null) continue;
|
|
286578
286862
|
let text;
|
|
286579
286863
|
try {
|
|
286580
|
-
text =
|
|
286864
|
+
text = readFileSync24(join43(cwd, file2), "utf8");
|
|
286581
286865
|
} catch {
|
|
286582
286866
|
continue;
|
|
286583
286867
|
}
|
|
@@ -286646,7 +286930,8 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286646
286930
|
cwd,
|
|
286647
286931
|
ctx.payload.moduleCatalogue,
|
|
286648
286932
|
ctx.toolState.orgModuleHcl
|
|
286649
|
-
);
|
|
286933
|
+
).filter((c) => ctx.payload.refactorExamples || !isExamplePath(c.cluster.file));
|
|
286934
|
+
const library = libraryRepoReason(cwd);
|
|
286650
286935
|
const matched = candidates.filter((c) => c.candidates.length > 0);
|
|
286651
286936
|
const reasons = {};
|
|
286652
286937
|
for (const c of candidates)
|
|
@@ -286660,6 +286945,7 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286660
286945
|
`\xBB module_extraction_candidates: ${candidates.length} cluster(s), ${matched.length} with a module match` + (partialInterfaces.length > 0 ? `, ${partialInterfaces.length} partial-interface block(s)` : "")
|
|
286661
286946
|
);
|
|
286662
286947
|
return toolOk({
|
|
286948
|
+
...reportOnly(library),
|
|
286663
286949
|
cluster_count: candidates.length,
|
|
286664
286950
|
matched_count: matched.length,
|
|
286665
286951
|
candidates,
|
|
@@ -286683,8 +286969,8 @@ function ModuleExtractionCandidatesTool(ctx) {
|
|
|
286683
286969
|
}
|
|
286684
286970
|
|
|
286685
286971
|
// src/mcp/moduleTests.ts
|
|
286686
|
-
import { existsSync as
|
|
286687
|
-
import { join as
|
|
286972
|
+
import { existsSync as existsSync11, readdirSync as readdirSync8, readFileSync as readFileSync25, statSync as statSync7 } from "node:fs";
|
|
286973
|
+
import { join as join44 } from "node:path";
|
|
286688
286974
|
var MODULE_META_ARGS = /* @__PURE__ */ new Set([
|
|
286689
286975
|
"source",
|
|
286690
286976
|
"version",
|
|
@@ -286804,30 +287090,30 @@ function resolveSourceDir(fromDir, source) {
|
|
|
286804
287090
|
}
|
|
286805
287091
|
function isDir(p) {
|
|
286806
287092
|
try {
|
|
286807
|
-
return
|
|
287093
|
+
return existsSync11(p) && statSync7(p).isDirectory();
|
|
286808
287094
|
} catch {
|
|
286809
287095
|
return false;
|
|
286810
287096
|
}
|
|
286811
287097
|
}
|
|
286812
287098
|
function listFiles(absDir, suffix2) {
|
|
286813
287099
|
try {
|
|
286814
|
-
return
|
|
287100
|
+
return readdirSync8(absDir).filter((f) => f.endsWith(suffix2)).sort();
|
|
286815
287101
|
} catch {
|
|
286816
287102
|
return [];
|
|
286817
287103
|
}
|
|
286818
287104
|
}
|
|
286819
287105
|
function listSubdirs(absDir) {
|
|
286820
287106
|
try {
|
|
286821
|
-
return
|
|
287107
|
+
return readdirSync8(absDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
286822
287108
|
} catch {
|
|
286823
287109
|
return [];
|
|
286824
287110
|
}
|
|
286825
287111
|
}
|
|
286826
287112
|
function readAllTf(cwd, relDir) {
|
|
286827
287113
|
let text = "";
|
|
286828
|
-
for (const f of listFiles(
|
|
287114
|
+
for (const f of listFiles(join44(cwd, relDir), ".tf")) {
|
|
286829
287115
|
try {
|
|
286830
|
-
text += `${
|
|
287116
|
+
text += `${readFileSync25(join44(cwd, relDir, f), "utf8")}
|
|
286831
287117
|
`;
|
|
286832
287118
|
} catch {
|
|
286833
287119
|
}
|
|
@@ -286839,8 +287125,8 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
286839
287125
|
const assets = [];
|
|
286840
287126
|
const matchesModule = (source, fromDir) => resolveSourceDir(fromDir, source) === md;
|
|
286841
287127
|
for (const examplesRoot of [`${md}/examples`, "examples"]) {
|
|
286842
|
-
if (!isDir(
|
|
286843
|
-
for (const sub of listSubdirs(
|
|
287128
|
+
if (!isDir(join44(cwd, examplesRoot))) continue;
|
|
287129
|
+
for (const sub of listSubdirs(join44(cwd, examplesRoot))) {
|
|
286844
287130
|
const exDir = `${examplesRoot}/${sub}`;
|
|
286845
287131
|
const hcl2 = readAllTf(cwd, exDir);
|
|
286846
287132
|
if (!hcl2) continue;
|
|
@@ -286856,12 +287142,12 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
286856
287142
|
}
|
|
286857
287143
|
}
|
|
286858
287144
|
for (const testDir of [`${md}/tests`, md]) {
|
|
286859
|
-
if (!isDir(
|
|
286860
|
-
for (const f of listFiles(
|
|
287145
|
+
if (!isDir(join44(cwd, testDir))) continue;
|
|
287146
|
+
for (const f of listFiles(join44(cwd, testDir), ".tftest.hcl")) {
|
|
286861
287147
|
const rel = `${testDir}/${f}`;
|
|
286862
287148
|
let hcl2;
|
|
286863
287149
|
try {
|
|
286864
|
-
hcl2 =
|
|
287150
|
+
hcl2 = readFileSync25(join44(cwd, rel), "utf8");
|
|
286865
287151
|
} catch {
|
|
286866
287152
|
continue;
|
|
286867
287153
|
}
|
|
@@ -286869,12 +287155,12 @@ function discoverModuleTestAssets(cwd, moduleDir) {
|
|
|
286869
287155
|
}
|
|
286870
287156
|
}
|
|
286871
287157
|
for (const goDir of [`${md}/test`, `${md}/tests`]) {
|
|
286872
|
-
if (!isDir(
|
|
286873
|
-
for (const f of listFiles(
|
|
287158
|
+
if (!isDir(join44(cwd, goDir))) continue;
|
|
287159
|
+
for (const f of listFiles(join44(cwd, goDir), "_test.go")) {
|
|
286874
287160
|
const rel = `${goDir}/${f}`;
|
|
286875
287161
|
let go;
|
|
286876
287162
|
try {
|
|
286877
|
-
go =
|
|
287163
|
+
go = readFileSync25(join44(cwd, rel), "utf8");
|
|
286878
287164
|
} catch {
|
|
286879
287165
|
continue;
|
|
286880
287166
|
}
|
|
@@ -286998,8 +287284,8 @@ function SetOutputTool(ctx, outputSchema) {
|
|
|
286998
287284
|
|
|
286999
287285
|
// src/mcp/policy.ts
|
|
287000
287286
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
287001
|
-
import { existsSync as
|
|
287002
|
-
import { join as
|
|
287287
|
+
import { existsSync as existsSync12, readFileSync as readFileSync26 } from "node:fs";
|
|
287288
|
+
import { join as join45 } from "node:path";
|
|
287003
287289
|
function parseConftestOutput(stdout) {
|
|
287004
287290
|
let parsed2;
|
|
287005
287291
|
try {
|
|
@@ -287033,7 +287319,7 @@ var CONFTEST_CONFIG = "conftest.toml";
|
|
|
287033
287319
|
function conftestSelectsNamespaces(conftestCwd) {
|
|
287034
287320
|
let raw2;
|
|
287035
287321
|
try {
|
|
287036
|
-
raw2 =
|
|
287322
|
+
raw2 = readFileSync26(join45(conftestCwd, CONFTEST_CONFIG), "utf-8");
|
|
287037
287323
|
} catch {
|
|
287038
287324
|
return false;
|
|
287039
287325
|
}
|
|
@@ -287049,8 +287335,8 @@ function namespaceArgs(conftestCwd) {
|
|
|
287049
287335
|
}
|
|
287050
287336
|
function findPlanJson(cwd) {
|
|
287051
287337
|
for (const candidate of PLAN_JSON_NAMES) {
|
|
287052
|
-
const abs =
|
|
287053
|
-
if (
|
|
287338
|
+
const abs = join45(cwd, candidate);
|
|
287339
|
+
if (existsSync12(abs)) return abs;
|
|
287054
287340
|
}
|
|
287055
287341
|
return null;
|
|
287056
287342
|
}
|
|
@@ -287091,11 +287377,11 @@ function resolvePolicyDir(cwd, explicit) {
|
|
|
287091
287377
|
} catch {
|
|
287092
287378
|
return null;
|
|
287093
287379
|
}
|
|
287094
|
-
return
|
|
287380
|
+
return existsSync12(abs) ? abs : null;
|
|
287095
287381
|
}
|
|
287096
287382
|
for (const d of DEFAULT_POLICY_DIRS) {
|
|
287097
|
-
const abs =
|
|
287098
|
-
if (
|
|
287383
|
+
const abs = join45(cwd, d);
|
|
287384
|
+
if (existsSync12(abs)) return abs;
|
|
287099
287385
|
}
|
|
287100
287386
|
return null;
|
|
287101
287387
|
}
|
|
@@ -287129,7 +287415,7 @@ function PolicyCheckTool(ctx) {
|
|
|
287129
287415
|
} catch {
|
|
287130
287416
|
abs = null;
|
|
287131
287417
|
}
|
|
287132
|
-
targetFile = abs &&
|
|
287418
|
+
targetFile = abs && existsSync12(abs) ? abs : null;
|
|
287133
287419
|
if (!targetFile) {
|
|
287134
287420
|
return toolSkip(
|
|
287135
287421
|
"target_not_found",
|
|
@@ -287402,9 +287688,9 @@ function PullRequestInfoTool(ctx) {
|
|
|
287402
287688
|
|
|
287403
287689
|
// node_modules/.pnpm/@infraweaver-io+sandbox@0.1.8/node_modules/@infraweaver-io/sandbox/dist/writePolicy.js
|
|
287404
287690
|
import { renameSync, writeFileSync as writeFileSync13 } from "node:fs";
|
|
287405
|
-
import { join as
|
|
287691
|
+
import { join as join46 } from "node:path";
|
|
287406
287692
|
function writePolicyPath(tmpdir5, filename) {
|
|
287407
|
-
return
|
|
287693
|
+
return join46(tmpdir5, filename);
|
|
287408
287694
|
}
|
|
287409
287695
|
function publishWritePolicy(params) {
|
|
287410
287696
|
try {
|
|
@@ -287575,12 +287861,12 @@ function SelectModeTool(ctx) {
|
|
|
287575
287861
|
}
|
|
287576
287862
|
|
|
287577
287863
|
// src/mcp/terraform/tools/advise.ts
|
|
287578
|
-
import { existsSync as
|
|
287579
|
-
import { join as
|
|
287864
|
+
import { existsSync as existsSync13, readFileSync as readFileSync28 } from "node:fs";
|
|
287865
|
+
import { join as join48 } from "node:path";
|
|
287580
287866
|
|
|
287581
287867
|
// src/mcp/terraform/fixMemory.ts
|
|
287582
|
-
import { readFileSync as
|
|
287583
|
-
import { join as
|
|
287868
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
287869
|
+
import { join as join47 } from "node:path";
|
|
287584
287870
|
var FIX_MEMORY_FILENAME = FIX_MEMORY_FILE;
|
|
287585
287871
|
var MAX_DESCRIPTION = 400;
|
|
287586
287872
|
var MAX_BEFORE_EXAMPLE = 1200;
|
|
@@ -287667,7 +287953,7 @@ function loadFixMemory(cwd) {
|
|
|
287667
287953
|
const root = cwd ?? process.cwd();
|
|
287668
287954
|
for (const filename of [FIX_MEMORY_FILENAME, LEGACY_FIX_MEMORY_FILENAME]) {
|
|
287669
287955
|
try {
|
|
287670
|
-
return parseFixMemory(
|
|
287956
|
+
return parseFixMemory(readFileSync27(join47(root, filename), "utf-8")) ?? [];
|
|
287671
287957
|
} catch {
|
|
287672
287958
|
}
|
|
287673
287959
|
}
|
|
@@ -287733,10 +288019,10 @@ function inlineWaivers(content, file2) {
|
|
|
287733
288019
|
];
|
|
287734
288020
|
}
|
|
287735
288021
|
function readLearnings(tmpdir5) {
|
|
287736
|
-
const path15 =
|
|
287737
|
-
if (!
|
|
288022
|
+
const path15 = join48(tmpdir5, LEARNINGS_FILE);
|
|
288023
|
+
if (!existsSync13(path15)) return [];
|
|
287738
288024
|
try {
|
|
287739
|
-
return
|
|
288025
|
+
return readFileSync28(path15, "utf-8").split("\n");
|
|
287740
288026
|
} catch {
|
|
287741
288027
|
return [];
|
|
287742
288028
|
}
|
|
@@ -287755,7 +288041,7 @@ function runAdvise(ctx, input2) {
|
|
|
287755
288041
|
const learnings = readLearnings(ctx.tmpdir);
|
|
287756
288042
|
const openConcerns = session.lastScanConcerns;
|
|
287757
288043
|
const dossiers = files.map((file2) => {
|
|
287758
|
-
const content = readTextCapped(
|
|
288044
|
+
const content = readTextCapped(join48(cwd, file2));
|
|
287759
288045
|
const inline = content === null ? [] : inlineWaivers(content, file2);
|
|
287760
288046
|
const reviewedInline = reviewedCopy(
|
|
287761
288047
|
cwd,
|
|
@@ -289073,7 +289359,10 @@ function ConsolidationCandidatesTool(ctx) {
|
|
|
289073
289359
|
parameters: ConsolidationCandidatesParams,
|
|
289074
289360
|
execute: execute(async () => {
|
|
289075
289361
|
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
289076
|
-
const
|
|
289362
|
+
const tree = readWorkingTree(cwd);
|
|
289363
|
+
const result = findConsolidationGroups(
|
|
289364
|
+
ctx.payload.refactorExamples ? tree : tree.filter((f) => !isExamplePath(f.path))
|
|
289365
|
+
);
|
|
289077
289366
|
log2.info(
|
|
289078
289367
|
`\xBB terraform_consolidation_candidates: ${result.groups.length} group(s), ${result.near_groups.length} near-group(s), ${result.declined_groups.length} declined`
|
|
289079
289368
|
);
|
|
@@ -289090,8 +289379,8 @@ function ConsolidationCandidatesTool(ctx) {
|
|
|
289090
289379
|
}
|
|
289091
289380
|
|
|
289092
289381
|
// src/mcp/terraform/tools/detectPlanDrift.ts
|
|
289093
|
-
import { readFileSync as
|
|
289094
|
-
import { join as
|
|
289382
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
289383
|
+
import { join as join49 } from "node:path";
|
|
289095
289384
|
|
|
289096
289385
|
// src/mcp/terraform/cspm.ts
|
|
289097
289386
|
var ExternalResource = type({
|
|
@@ -289509,7 +289798,7 @@ function readTfFiles(cwd) {
|
|
|
289509
289798
|
const out = [];
|
|
289510
289799
|
for (const file2 of walkTfFiles(cwd)) {
|
|
289511
289800
|
try {
|
|
289512
|
-
out.push({ file: file2, hcl:
|
|
289801
|
+
out.push({ file: file2, hcl: readFileSync29(join49(cwd, file2), "utf8") });
|
|
289513
289802
|
} catch {
|
|
289514
289803
|
}
|
|
289515
289804
|
}
|
|
@@ -289526,7 +289815,7 @@ function DetectPlanDriftTool(ctx) {
|
|
|
289526
289815
|
const planPath = path15 || !envPlanPath ? resolveWithinCwd(cwd, path15 ?? "plan.json") : envPlanPath;
|
|
289527
289816
|
let raw2;
|
|
289528
289817
|
try {
|
|
289529
|
-
raw2 =
|
|
289818
|
+
raw2 = readFileSync29(planPath, "utf8");
|
|
289530
289819
|
} catch {
|
|
289531
289820
|
return skipResult(
|
|
289532
289821
|
"plan_artifact_not_found",
|
|
@@ -289658,13 +289947,13 @@ function DetectPlanDriftTool(ctx) {
|
|
|
289658
289947
|
}
|
|
289659
289948
|
|
|
289660
289949
|
// src/mcp/terraform/tools/emitCost.ts
|
|
289661
|
-
import { readFileSync as
|
|
289662
|
-
import { join as
|
|
289950
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync14 } from "node:fs";
|
|
289951
|
+
import { join as join50 } from "node:path";
|
|
289663
289952
|
|
|
289664
289953
|
// src/mcp/terraform/awsPrices.ts
|
|
289665
289954
|
var AWS_PRICE_REGION = "eu-west-2";
|
|
289666
289955
|
var AWS_PRICE_CURRENCY = "USD";
|
|
289667
|
-
var AWS_PRICE_FETCHED_AT = "2026-
|
|
289956
|
+
var AWS_PRICE_FETCHED_AT = "2026-10-03";
|
|
289668
289957
|
var AWS_HOURLY_PRICES = {
|
|
289669
289958
|
"eks-cluster-standard": 0.1,
|
|
289670
289959
|
"elb-application": 0.02646,
|
|
@@ -289682,30 +289971,30 @@ var AWS_PER_GB_PRICES = {
|
|
|
289682
289971
|
// src/mcp/terraform/azurePrices.ts
|
|
289683
289972
|
var AZURE_PRICE_REGION = "westeurope";
|
|
289684
289973
|
var AZURE_PRICE_CURRENCY = "EUR";
|
|
289685
|
-
var AZURE_PRICE_FETCHED_AT = "2026-
|
|
289974
|
+
var AZURE_PRICE_FETCHED_AT = "2026-10-03";
|
|
289686
289975
|
var AZURE_HOURLY_PRICES = {
|
|
289687
|
-
"app-service-p0v3": 0.
|
|
289688
|
-
"app-service-p1v3": 0.
|
|
289689
|
-
"app-service-p2v3": 0.
|
|
289690
|
-
"app-service-p3v3": 0.
|
|
289691
|
-
"bastion-basic": 0.
|
|
289692
|
-
"bastion-premium": 0.
|
|
289693
|
-
"bastion-standard": 0.
|
|
289694
|
-
"firewall-basic": 0.
|
|
289695
|
-
"firewall-premium": 1.
|
|
289696
|
-
"firewall-standard": 1.
|
|
289697
|
-
"redis-c0": 0.
|
|
289698
|
-
"redis-c1": 0.
|
|
289699
|
-
"redis-c2": 0.
|
|
289700
|
-
"redis-c3": 0.
|
|
289701
|
-
"redis-p1": 0.
|
|
289702
|
-
"redis-p2": 0.
|
|
289703
|
-
"redis-p3": 0.
|
|
289704
|
-
"vpn-gateway-vpngw1": 0.
|
|
289705
|
-
"vpn-gateway-vpngw2": 0.
|
|
289706
|
-
"vpn-gateway-vpngw3": 1.
|
|
289707
|
-
"vpn-gateway-vpngw4": 1.
|
|
289708
|
-
"vpn-gateway-vpngw5": 3.
|
|
289976
|
+
"app-service-p0v3": 0.0783,
|
|
289977
|
+
"app-service-p1v3": 0.1566,
|
|
289978
|
+
"app-service-p2v3": 0.3133,
|
|
289979
|
+
"app-service-p3v3": 0.6265,
|
|
289980
|
+
"bastion-basic": 0.1672,
|
|
289981
|
+
"bastion-premium": 0.396,
|
|
289982
|
+
"bastion-standard": 0.2552,
|
|
289983
|
+
"firewall-basic": 0.3476,
|
|
289984
|
+
"firewall-premium": 1.54,
|
|
289985
|
+
"firewall-standard": 1.1,
|
|
289986
|
+
"redis-c0": 0.0242,
|
|
289987
|
+
"redis-c1": 0.0607,
|
|
289988
|
+
"redis-c2": 0.0986,
|
|
289989
|
+
"redis-c3": 0.198,
|
|
289990
|
+
"redis-p1": 0.2438,
|
|
289991
|
+
"redis-p2": 0.4884,
|
|
289992
|
+
"redis-p3": 0.9759,
|
|
289993
|
+
"vpn-gateway-vpngw1": 0.1672,
|
|
289994
|
+
"vpn-gateway-vpngw2": 0.4312,
|
|
289995
|
+
"vpn-gateway-vpngw3": 1.1,
|
|
289996
|
+
"vpn-gateway-vpngw4": 1.8479,
|
|
289997
|
+
"vpn-gateway-vpngw5": 3.2119
|
|
289709
289998
|
};
|
|
289710
289999
|
|
|
289711
290000
|
// src/mcp/terraform/idleFloor.ts
|
|
@@ -289983,7 +290272,7 @@ function readTfFiles2(cwd) {
|
|
|
289983
290272
|
const out = [];
|
|
289984
290273
|
for (const file2 of walkTfFiles(cwd)) {
|
|
289985
290274
|
try {
|
|
289986
|
-
out.push({ file: file2, hcl:
|
|
290275
|
+
out.push({ file: file2, hcl: readFileSync30(join50(cwd, file2), "utf8") });
|
|
289987
290276
|
} catch {
|
|
289988
290277
|
}
|
|
289989
290278
|
}
|
|
@@ -291247,7 +291536,7 @@ function TerraformEmitVexTool(ctx) {
|
|
|
291247
291536
|
// src/mcp/terraform/tools/equivalenceCheck.ts
|
|
291248
291537
|
import { mkdtempSync as mkdtempSync5, rmSync as rmSync7 } from "node:fs";
|
|
291249
291538
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
291250
|
-
import { join as
|
|
291539
|
+
import { join as join51 } from "node:path";
|
|
291251
291540
|
|
|
291252
291541
|
// src/mcp/terraform/refactor/attribution.ts
|
|
291253
291542
|
import { posix as posix13 } from "node:path";
|
|
@@ -293039,12 +293328,12 @@ async function baselineValidateErrors(cwd, base, env2, session) {
|
|
|
293039
293328
|
}
|
|
293040
293329
|
const prefix2 = run("git", ["rev-parse", "--show-prefix"], cwd);
|
|
293041
293330
|
if (prefix2.status !== 0) return null;
|
|
293042
|
-
const tree = mkdtempSync5(
|
|
293331
|
+
const tree = mkdtempSync5(join51(tmpdir3(), "iw-baseline-"));
|
|
293043
293332
|
try {
|
|
293044
293333
|
if (run("git", ["worktree", "add", "--detach", "--quiet", tree, base], cwd).status !== 0) {
|
|
293045
293334
|
return null;
|
|
293046
293335
|
}
|
|
293047
|
-
const outcome2 = await scanValidate(
|
|
293336
|
+
const outcome2 = await scanValidate(join51(tree, prefix2.stdout.trim()), env2);
|
|
293048
293337
|
if (!outcome2.ran || outcome2.unvalidated) return null;
|
|
293049
293338
|
const errors = outcome2.concerns.map(validateErrorKey);
|
|
293050
293339
|
session.baselineValidateErrors = { base, errors };
|
|
@@ -293145,7 +293434,7 @@ function TerraformGenerateMovedTool(ctx) {
|
|
|
293145
293434
|
|
|
293146
293435
|
// src/mcp/terraform/cost.ts
|
|
293147
293436
|
import { mkdtempSync as mkdtempSync6, rmSync as rmSync8 } from "node:fs";
|
|
293148
|
-
import { join as
|
|
293437
|
+
import { join as join52 } from "node:path";
|
|
293149
293438
|
function parseInfracostBreakdown(stdout) {
|
|
293150
293439
|
const parsed2 = parseScannerJson(InfracostBreakdownOutput, stdout, "infracost");
|
|
293151
293440
|
const raw2 = parsed2.totalMonthlyCost;
|
|
@@ -293227,15 +293516,15 @@ async function infracostBaseline(cwd, key, tmpdir5) {
|
|
|
293227
293516
|
if (!baseRef) return null;
|
|
293228
293517
|
const prefixResult = run("git", ["rev-parse", "--show-prefix"], cwd);
|
|
293229
293518
|
const prefix2 = prefixResult.status === 0 ? prefixResult.stdout.trim() : "";
|
|
293230
|
-
const baseDir = mkdtempSync6(
|
|
293231
|
-
const worktree =
|
|
293519
|
+
const baseDir = mkdtempSync6(join52(tmpdir5, "infracost-base-"));
|
|
293520
|
+
const worktree = join52(baseDir, "wt");
|
|
293232
293521
|
const add = run("git", ["worktree", "add", "--detach", worktree, baseRef], cwd);
|
|
293233
293522
|
if (add.status !== 0) {
|
|
293234
293523
|
rmSync8(baseDir, { recursive: true, force: true });
|
|
293235
293524
|
return null;
|
|
293236
293525
|
}
|
|
293237
293526
|
try {
|
|
293238
|
-
const scanCwd = prefix2 ?
|
|
293527
|
+
const scanCwd = prefix2 ? join52(worktree, prefix2) : worktree;
|
|
293239
293528
|
const r = await runInfracostBreakdown(scanCwd, key);
|
|
293240
293529
|
if (r.missing || r.status !== 0) return null;
|
|
293241
293530
|
return parseInfracostBreakdown(r.stdout);
|
|
@@ -293305,8 +293594,8 @@ function InfracostDiffTool(ctx) {
|
|
|
293305
293594
|
}
|
|
293306
293595
|
|
|
293307
293596
|
// src/mcp/terraform/tools/ingestExternalFindings.ts
|
|
293308
|
-
import { statSync as
|
|
293309
|
-
import { join as
|
|
293597
|
+
import { statSync as statSync8 } from "node:fs";
|
|
293598
|
+
import { join as join53 } from "node:path";
|
|
293310
293599
|
|
|
293311
293600
|
// src/mcp/terraform/prowlerOcsf.ts
|
|
293312
293601
|
var DETECTION_FINDING_CREATE = 200401;
|
|
@@ -293532,7 +293821,7 @@ var MAX_FEED_BYTES = 100 * 1024 * 1024;
|
|
|
293532
293821
|
function readTfFiles3(cwd) {
|
|
293533
293822
|
const out = [];
|
|
293534
293823
|
for (const file2 of walkTfFiles(cwd)) {
|
|
293535
|
-
const hcl2 = readTextCapped(
|
|
293824
|
+
const hcl2 = readTextCapped(join53(cwd, file2));
|
|
293536
293825
|
if (hcl2 !== null) out.push({ file: file2, hcl: hcl2 });
|
|
293537
293826
|
}
|
|
293538
293827
|
return out;
|
|
@@ -293560,7 +293849,7 @@ function IngestExternalFindingsTool(ctx) {
|
|
|
293560
293849
|
return unusableFeed("external_findings_outside_workspace", errorMessage(error63));
|
|
293561
293850
|
}
|
|
293562
293851
|
try {
|
|
293563
|
-
const size =
|
|
293852
|
+
const size = statSync8(feedPath).size;
|
|
293564
293853
|
if (size > MAX_FEED_BYTES) {
|
|
293565
293854
|
return unusableFeed(
|
|
293566
293855
|
"external_findings_too_large",
|
|
@@ -293689,8 +293978,8 @@ function IngestExternalFindingsTool(ctx) {
|
|
|
293689
293978
|
}
|
|
293690
293979
|
|
|
293691
293980
|
// src/mcp/terraform/tools/moduleDocs.ts
|
|
293692
|
-
import { readFileSync as
|
|
293693
|
-
import { join as
|
|
293981
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync16 } from "node:fs";
|
|
293982
|
+
import { join as join54 } from "node:path";
|
|
293694
293983
|
|
|
293695
293984
|
// src/mcp/terraform/moduleDocs.ts
|
|
293696
293985
|
var VERDICT_CLAIM = {
|
|
@@ -293804,7 +294093,7 @@ function TerraformModuleDocsTool(ctx) {
|
|
|
293804
294093
|
);
|
|
293805
294094
|
}
|
|
293806
294095
|
const absDir = resolveWithinCwd(cwd, module_dir);
|
|
293807
|
-
const target =
|
|
294096
|
+
const target = join54(absDir, "README.md");
|
|
293808
294097
|
let gitHead = null;
|
|
293809
294098
|
try {
|
|
293810
294099
|
gitHead = $("git", ["rev-parse", "HEAD"], { cwd, log: false });
|
|
@@ -293812,7 +294101,7 @@ function TerraformModuleDocsTool(ctx) {
|
|
|
293812
294101
|
}
|
|
293813
294102
|
let existing = null;
|
|
293814
294103
|
try {
|
|
293815
|
-
existing =
|
|
294104
|
+
existing = readFileSync31(target, "utf8");
|
|
293816
294105
|
} catch {
|
|
293817
294106
|
}
|
|
293818
294107
|
const priorHead = readFooterGitHead(existing);
|
|
@@ -294116,12 +294405,15 @@ function NormalizationCandidatesTool(ctx) {
|
|
|
294116
294405
|
parameters: NormalizationCandidatesParams,
|
|
294117
294406
|
execute: execute(async () => {
|
|
294118
294407
|
const cwd = ctx.payload.cwd ?? process.cwd();
|
|
294119
|
-
const files = findNormalizationCandidates(cwd)
|
|
294408
|
+
const files = findNormalizationCandidates(cwd).filter(
|
|
294409
|
+
(f) => ctx.payload.refactorExamples || !isExamplePath(f.file)
|
|
294410
|
+
);
|
|
294120
294411
|
const total = files.reduce((n, f) => n + f.count, 0);
|
|
294121
294412
|
log2.info(
|
|
294122
294413
|
`\xBB terraform_normalization_candidates: ${total} site(s) across ${files.length} file(s)`
|
|
294123
294414
|
);
|
|
294124
294415
|
return toolOk({
|
|
294416
|
+
...reportOnly(libraryRepoReason(cwd)),
|
|
294125
294417
|
file_count: files.length,
|
|
294126
294418
|
total,
|
|
294127
294419
|
files,
|
|
@@ -294133,7 +294425,7 @@ function NormalizationCandidatesTool(ctx) {
|
|
|
294133
294425
|
|
|
294134
294426
|
// src/mcp/terraform/tools/plan.ts
|
|
294135
294427
|
import { rmSync as rmSync9 } from "node:fs";
|
|
294136
|
-
import { join as
|
|
294428
|
+
import { join as join55 } from "node:path";
|
|
294137
294429
|
var PLAN_JSON_ARGS = ["plan", "-input=false", "-no-color", "-lock=false", "-json"];
|
|
294138
294430
|
var planFileSeq = 0;
|
|
294139
294431
|
async function capturePlanPairs(absDir, planFile, creds) {
|
|
@@ -294156,7 +294448,7 @@ async function planOneRoot(absDir, creds, tmpdir5) {
|
|
|
294156
294448
|
skipReason: `terraform init failed: ${init.stderr.trim().slice(0, 200) || "unknown error"}`
|
|
294157
294449
|
};
|
|
294158
294450
|
}
|
|
294159
|
-
const planFile = tmpdir5 ?
|
|
294451
|
+
const planFile = tmpdir5 ? join55(tmpdir5, `plan-${process.pid}-${planFileSeq++}.tfplan`) : void 0;
|
|
294160
294452
|
const plan = await runTfAsync(
|
|
294161
294453
|
planFile ? [...PLAN_JSON_ARGS, `-out=${planFile}`] : PLAN_JSON_ARGS,
|
|
294162
294454
|
absDir,
|
|
@@ -294526,8 +294818,8 @@ function TerraformProviderUpgradeTool(ctx) {
|
|
|
294526
294818
|
}
|
|
294527
294819
|
|
|
294528
294820
|
// src/mcp/terraform/tfquery.ts
|
|
294529
|
-
import { readFileSync as
|
|
294530
|
-
import { join as
|
|
294821
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
294822
|
+
import { join as join56 } from "node:path";
|
|
294531
294823
|
var TFQUERY_SUFFIX = ".tfquery.hcl";
|
|
294532
294824
|
function parseQueryFile(hcl2) {
|
|
294533
294825
|
return parseBlocks(hcl2, ["list"]).map((block) => {
|
|
@@ -294553,7 +294845,7 @@ function collectQueryInventory(cwd) {
|
|
|
294553
294845
|
for (const rel of walkFilesBySuffix(cwd, TFQUERY_SUFFIX)) {
|
|
294554
294846
|
let text;
|
|
294555
294847
|
try {
|
|
294556
|
-
text =
|
|
294848
|
+
text = readFileSync32(join56(cwd, rel), "utf8");
|
|
294557
294849
|
} catch {
|
|
294558
294850
|
continue;
|
|
294559
294851
|
}
|
|
@@ -294588,7 +294880,7 @@ function TerraformQueryInventoryTool(ctx) {
|
|
|
294588
294880
|
}
|
|
294589
294881
|
|
|
294590
294882
|
// src/mcp/terraform/tools/readFindings.ts
|
|
294591
|
-
import { readFileSync as
|
|
294883
|
+
import { readFileSync as readFileSync33 } from "node:fs";
|
|
294592
294884
|
var ReadFindingsParams = type({
|
|
294593
294885
|
"path?": type.string.describe(
|
|
294594
294886
|
"path to the Assessor's findings.json. Defaults to $INFRAWEAVER_FINDINGS_PATH, then ./findings.json in the workspace."
|
|
@@ -294613,7 +294905,7 @@ function ReadFindingsTool(ctx) {
|
|
|
294613
294905
|
const findingsPath = path15 || !envFindingsPath ? resolveWithinCwd(cwd, path15 ?? "findings.json") : envFindingsPath;
|
|
294614
294906
|
let raw2;
|
|
294615
294907
|
try {
|
|
294616
|
-
raw2 =
|
|
294908
|
+
raw2 = readFileSync33(findingsPath, "utf8");
|
|
294617
294909
|
} catch {
|
|
294618
294910
|
return skipResult(
|
|
294619
294911
|
"findings_not_found",
|
|
@@ -294872,6 +295164,8 @@ var SUBJECT = {
|
|
|
294872
295164
|
// rule's silence a real statement. Whether git could answer is handled one
|
|
294873
295165
|
// level up by the blind set: a run that could not ask is never conforming.
|
|
294874
295166
|
"committed-state-file": ANY_BLOCK,
|
|
295167
|
+
// any block may hold a credential argument, a map of them, or a variable default
|
|
295168
|
+
"hardcoded-secret-argument": ANY_BLOCK,
|
|
294875
295169
|
"deprecated-s3-bucket-argument": /(?:^|\n)\s*resource\s+"?aws_s3_bucket(?:"|\s)/,
|
|
294876
295170
|
"superseded-resource-type": /(?:^|\n)\s*(?:resource\s+"?(?:aws_launch_configuration|aws_elb)(?:"|\s)|data\s+"?template_file(?:"|\s))/,
|
|
294877
295171
|
"missing-required-version": /(?:^|\n)\s*(?:resource|module|provider)\s+"/,
|
|
@@ -295289,7 +295583,25 @@ async function runVerifyRemediation(ctx, { concern_ids, download_external_module
|
|
|
295289
295583
|
if (key !== void 0) keyed.push({ id, key });
|
|
295290
295584
|
else unkeyed.push(id);
|
|
295291
295585
|
}
|
|
295292
|
-
const
|
|
295586
|
+
const byKey = partitionByKey(keyed, currentKeys);
|
|
295587
|
+
const read3 = fileReader(cwd);
|
|
295588
|
+
const remainingKeyed = keyed.filter((k) => byKey.remaining.includes(k.id));
|
|
295589
|
+
const atSite = new Set(
|
|
295590
|
+
resolvedAtSite({
|
|
295591
|
+
requested: remainingKeyed.map((k) => ({
|
|
295592
|
+
...k,
|
|
295593
|
+
site: session.siteById?.get(k.id) ?? null,
|
|
295594
|
+
file: reported.get(k.id)?.location.file
|
|
295595
|
+
})),
|
|
295596
|
+
current: currentConcerns.map((c) => ({ key: concernKeyOf(c), site: siteOf(c, read3) })),
|
|
295597
|
+
firstSites: session.firstSitesByKey ?? /* @__PURE__ */ new Map(),
|
|
295598
|
+
declared: (file2) => new Set(declaredAddresses2(read3(file2) ?? ""))
|
|
295599
|
+
})
|
|
295600
|
+
);
|
|
295601
|
+
const keyedVerdict = {
|
|
295602
|
+
resolved: [...byKey.resolved, ...byKey.remaining.filter((id) => atSite.has(id))],
|
|
295603
|
+
remaining: byKey.remaining.filter((id) => !atSite.has(id))
|
|
295604
|
+
};
|
|
295293
295605
|
const fallbackVerdict = computeRemediationVerdict(unkeyed, new Set(currentIds));
|
|
295294
295606
|
const resolved = [...keyedVerdict.resolved, ...fallbackVerdict.resolved];
|
|
295295
295607
|
const remaining = [...keyedVerdict.remaining, ...fallbackVerdict.remaining];
|
|
@@ -298543,15 +298855,15 @@ async function startMcpHttpServer(ctx, options) {
|
|
|
298543
298855
|
|
|
298544
298856
|
// src/mcp/terraform/policyGate.ts
|
|
298545
298857
|
import {
|
|
298546
|
-
existsSync as
|
|
298858
|
+
existsSync as existsSync14,
|
|
298547
298859
|
mkdirSync as mkdirSync7,
|
|
298548
298860
|
mkdtempSync as mkdtempSync7,
|
|
298549
|
-
readdirSync as
|
|
298550
|
-
readFileSync as
|
|
298861
|
+
readdirSync as readdirSync9,
|
|
298862
|
+
readFileSync as readFileSync35,
|
|
298551
298863
|
writeFileSync as writeFileSync17
|
|
298552
298864
|
} from "node:fs";
|
|
298553
298865
|
import { tmpdir as osTmpdir } from "node:os";
|
|
298554
|
-
import { dirname as dirname8, isAbsolute as isAbsolute6, join as
|
|
298866
|
+
import { dirname as dirname8, isAbsolute as isAbsolute6, join as join58, relative as relative6, resolve as resolve8 } from "node:path";
|
|
298555
298867
|
function coercePolicyRules(raw2) {
|
|
298556
298868
|
const rules = [];
|
|
298557
298869
|
const rejected = [];
|
|
@@ -298579,7 +298891,7 @@ var UNKNOWN2 = /* @__PURE__ */ Symbol("unknown");
|
|
|
298579
298891
|
function isScalar(v) {
|
|
298580
298892
|
return typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
298581
298893
|
}
|
|
298582
|
-
function
|
|
298894
|
+
function literalValue2(raw2) {
|
|
298583
298895
|
const v = raw2.includes("\n") ? raw2.trim() : stripTrailingComment(raw2);
|
|
298584
298896
|
if (v === "true") return true;
|
|
298585
298897
|
if (v === "false") return false;
|
|
@@ -298612,7 +298924,7 @@ function objectLiteral(v) {
|
|
|
298612
298924
|
for (const line of lines) {
|
|
298613
298925
|
const m = OBJECT_LINE.exec(line);
|
|
298614
298926
|
if (!m) return UNKNOWN2;
|
|
298615
|
-
const value2 =
|
|
298927
|
+
const value2 = literalValue2(m[3] ?? "");
|
|
298616
298928
|
if (value2 !== void 0) out[m[1] ?? m[2]] = value2;
|
|
298617
298929
|
}
|
|
298618
298930
|
return out;
|
|
@@ -298640,7 +298952,7 @@ function staticValues(body2) {
|
|
|
298640
298952
|
continue;
|
|
298641
298953
|
}
|
|
298642
298954
|
if (e.kind === "attr") {
|
|
298643
|
-
const value2 =
|
|
298955
|
+
const value2 = literalValue2(e.value ?? "");
|
|
298644
298956
|
if (value2 !== void 0) out[e.name] = value2;
|
|
298645
298957
|
continue;
|
|
298646
298958
|
}
|
|
@@ -298803,7 +299115,7 @@ function evaluateRulesStatically(cwd, rules, scope2 = { kind: "all", reason: ""
|
|
|
298803
299115
|
const files = [];
|
|
298804
299116
|
for (const rel of walk.files) {
|
|
298805
299117
|
try {
|
|
298806
|
-
files.push({ rel, text:
|
|
299118
|
+
files.push({ rel, text: readFileSync35(join58(cwd, rel), "utf-8") });
|
|
298807
299119
|
} catch {
|
|
298808
299120
|
}
|
|
298809
299121
|
}
|
|
@@ -298918,16 +299230,16 @@ function cloudEmittedRego(rules) {
|
|
|
298918
299230
|
}
|
|
298919
299231
|
function readOrEmpty(path15) {
|
|
298920
299232
|
try {
|
|
298921
|
-
return
|
|
299233
|
+
return readFileSync35(path15, "utf-8");
|
|
298922
299234
|
} catch {
|
|
298923
299235
|
return "";
|
|
298924
299236
|
}
|
|
298925
299237
|
}
|
|
298926
299238
|
function regoDirIn(root, skip) {
|
|
298927
299239
|
for (const dir of DEFAULT_POLICY_DIRS) {
|
|
298928
|
-
const abs =
|
|
298929
|
-
if (
|
|
298930
|
-
(rel) => !skip(
|
|
299240
|
+
const abs = join58(root, dir);
|
|
299241
|
+
if (existsSync14(abs) && walkFilesBySuffix(abs, ".rego").some(
|
|
299242
|
+
(rel) => !skip(join58(dir, rel), readOrEmpty(join58(abs, rel)))
|
|
298931
299243
|
)) {
|
|
298932
299244
|
return dir;
|
|
298933
299245
|
}
|
|
@@ -298935,14 +299247,14 @@ function regoDirIn(root, skip) {
|
|
|
298935
299247
|
return null;
|
|
298936
299248
|
}
|
|
298937
299249
|
function withoutSkipped(root, dir, skip, tmpdir5) {
|
|
298938
|
-
const abs =
|
|
298939
|
-
const files =
|
|
298940
|
-
const kept = files.filter((rel) => !skip(
|
|
299250
|
+
const abs = join58(root, dir);
|
|
299251
|
+
const files = readdirSync9(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile()).map((e) => relative6(abs, join58(e.parentPath, e.name)));
|
|
299252
|
+
const kept = files.filter((rel) => !skip(join58(dir, rel), readOrEmpty(join58(abs, rel))));
|
|
298941
299253
|
if (kept.length === files.length) return abs;
|
|
298942
|
-
const copy =
|
|
299254
|
+
const copy = join58(mkdtempSync7(join58(tmpdir5 ?? osTmpdir(), "policy-own-")), dir);
|
|
298943
299255
|
for (const rel of kept) {
|
|
298944
|
-
mkdirSync7(dirname8(
|
|
298945
|
-
writeFileSync17(
|
|
299256
|
+
mkdirSync7(dirname8(join58(copy, rel)), { recursive: true });
|
|
299257
|
+
writeFileSync17(join58(copy, rel), readFileSync35(join58(abs, rel)));
|
|
298946
299258
|
}
|
|
298947
299259
|
return copy;
|
|
298948
299260
|
}
|
|
@@ -298964,18 +299276,18 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
298964
299276
|
}
|
|
298965
299277
|
const own2 = tree.files.filter((f) => !skip(f.path, f.raw));
|
|
298966
299278
|
if (!own2.some((f) => f.path.endsWith(".rego"))) continue;
|
|
298967
|
-
const root = mkdtempSync7(
|
|
299279
|
+
const root = mkdtempSync7(join58(tmpdir5 ?? osTmpdir(), "policy-base-"));
|
|
298968
299280
|
for (const f of own2) {
|
|
298969
|
-
mkdirSync7(dirname8(
|
|
298970
|
-
writeFileSync17(
|
|
299281
|
+
mkdirSync7(dirname8(join58(root, f.path)), { recursive: true });
|
|
299282
|
+
writeFileSync17(join58(root, f.path), f.raw);
|
|
298971
299283
|
}
|
|
298972
299284
|
const toml = readFileAtBaseRef(cwd, baseRef, CONFTEST_CONFIG);
|
|
298973
|
-
if (toml.kind === "file") writeFileSync17(
|
|
298974
|
-
const same = head === dir &&
|
|
299285
|
+
if (toml.kind === "file") writeFileSync17(join58(root, CONFTEST_CONFIG), toml.raw);
|
|
299286
|
+
const same = head === dir && readdirSync9(join58(cwd, dir), { recursive: true, withFileTypes: true }).filter(
|
|
298975
299287
|
(e) => e.isFile()
|
|
298976
299288
|
).length === tree.files.length && tree.files.every((f) => {
|
|
298977
299289
|
try {
|
|
298978
|
-
return
|
|
299290
|
+
return readFileSync35(join58(cwd, f.path), "utf-8") === f.raw;
|
|
298979
299291
|
} catch {
|
|
298980
299292
|
return false;
|
|
298981
299293
|
}
|
|
@@ -298985,7 +299297,7 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
298985
299297
|
`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.`
|
|
298986
299298
|
);
|
|
298987
299299
|
}
|
|
298988
|
-
return { policyDir:
|
|
299300
|
+
return { policyDir: join58(root, dir), conftestCwd: root };
|
|
298989
299301
|
}
|
|
298990
299302
|
if (head) {
|
|
298991
299303
|
notes.push(
|
|
@@ -298995,7 +299307,7 @@ function resolveRepoPolicy(cwd, baseRef, tmpdir5, notes, skip) {
|
|
|
298995
299307
|
return null;
|
|
298996
299308
|
}
|
|
298997
299309
|
function findWorkflowPlanJson(cwd, notes) {
|
|
298998
|
-
const present = PLAN_JSON_NAMES.filter((name) =>
|
|
299310
|
+
const present = PLAN_JSON_NAMES.filter((name) => existsSync14(join58(cwd, name)));
|
|
298999
299311
|
if (present.length === 0) return null;
|
|
299000
299312
|
const listing = run("git", ["ls-files", "-z"], cwd);
|
|
299001
299313
|
if (listing.status !== 0) {
|
|
@@ -299012,7 +299324,7 @@ function findWorkflowPlanJson(cwd, notes) {
|
|
|
299012
299324
|
);
|
|
299013
299325
|
continue;
|
|
299014
299326
|
}
|
|
299015
|
-
return
|
|
299327
|
+
return join58(cwd, name);
|
|
299016
299328
|
}
|
|
299017
299329
|
return null;
|
|
299018
299330
|
}
|
|
@@ -299042,7 +299354,7 @@ function evaluatePolicyGate(cwd, rawRules, opts = {}) {
|
|
|
299042
299354
|
let plan;
|
|
299043
299355
|
if (planPath) {
|
|
299044
299356
|
try {
|
|
299045
|
-
plan = asPlan(JSON.parse(
|
|
299357
|
+
plan = asPlan(JSON.parse(readFileSync35(planPath, "utf-8")));
|
|
299046
299358
|
} catch {
|
|
299047
299359
|
}
|
|
299048
299360
|
if (!plan) notes.push(`${planPath} is not a Terraform plan JSON \u2014 ignored`);
|
|
@@ -299145,7 +299457,7 @@ function capturePolicyGate(ctx) {
|
|
|
299145
299457
|
if (!result) return;
|
|
299146
299458
|
const workspace = process.env.GITHUB_WORKSPACE ?? cwd;
|
|
299147
299459
|
for (const o of [...result.violations, ...result.inconclusive]) {
|
|
299148
|
-
if (o.file) o.file = posix16(relative6(workspace,
|
|
299460
|
+
if (o.file) o.file = posix16(relative6(workspace, join58(cwd, o.file)));
|
|
299149
299461
|
}
|
|
299150
299462
|
session.policyGate = result;
|
|
299151
299463
|
for (const n of result.notes) log2.warning(`\xBB policy gate: ${n}`);
|
|
@@ -299480,7 +299792,7 @@ var ThinkingTimer = class {
|
|
|
299480
299792
|
// src/agents/claude.ts
|
|
299481
299793
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
299482
299794
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync10, writeFileSync as writeFileSync22 } from "node:fs";
|
|
299483
|
-
import { join as
|
|
299795
|
+
import { join as join67 } from "node:path";
|
|
299484
299796
|
import { performance as performance6 } from "node:perf_hooks";
|
|
299485
299797
|
import { setTimeout as sleep6 } from "node:timers/promises";
|
|
299486
299798
|
|
|
@@ -299840,7 +300152,7 @@ import { readFile as readFile2 } from "node:fs/promises";
|
|
|
299840
300152
|
|
|
299841
300153
|
// src/agents/shared.ts
|
|
299842
300154
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
299843
|
-
import { join as
|
|
300155
|
+
import { join as join59 } from "node:path";
|
|
299844
300156
|
var MAX_STDERR_LINES = 20;
|
|
299845
300157
|
var MAX_POST_RUN_RETRIES = 3;
|
|
299846
300158
|
function getGitStatus() {
|
|
@@ -299877,7 +300189,7 @@ var agent = (input2) => {
|
|
|
299877
300189
|
};
|
|
299878
300190
|
};
|
|
299879
300191
|
function agentHomeEnv(tmpdir5) {
|
|
299880
|
-
return { HOME: tmpdir5, XDG_CONFIG_HOME:
|
|
300192
|
+
return { HOME: tmpdir5, XDG_CONFIG_HOME: join59(tmpdir5, ".config") };
|
|
299881
300193
|
}
|
|
299882
300194
|
function baseAgentEnv(homeEnv, repoDir) {
|
|
299883
300195
|
return { ...process.env, ...homeEnv, PWD: repoDir };
|
|
@@ -300353,6 +300665,12 @@ function shouldRunGraceTurn(params) {
|
|
|
300353
300665
|
return params.stopReason === "quota" && params.hasReserve && params.canResume && params.unsubmitted !== null;
|
|
300354
300666
|
}
|
|
300355
300667
|
|
|
300668
|
+
// src/agents/quotaTokens.ts
|
|
300669
|
+
var CACHE_READ_WEIGHT = 0.1;
|
|
300670
|
+
function quotaTokens(t) {
|
|
300671
|
+
return t.input + t.output + t.cacheWrite + t.cacheRead * CACHE_READ_WEIGHT;
|
|
300672
|
+
}
|
|
300673
|
+
|
|
300356
300674
|
// src/agents/sessionLabeler.ts
|
|
300357
300675
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
300358
300676
|
var ORCHESTRATOR_LABEL = "orchestrator";
|
|
@@ -300674,7 +300992,7 @@ function matchesRouteSentinel(envVar, model) {
|
|
|
300674
300992
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
300675
300993
|
import { mkdirSync as mkdirSync8, rmSync as rmSync10, writeFileSync as writeFileSync18 } from "node:fs";
|
|
300676
300994
|
import { homedir } from "node:os";
|
|
300677
|
-
import { join as
|
|
300995
|
+
import { join as join60 } from "node:path";
|
|
300678
300996
|
var VERTEX_SERVICE_ACCOUNT_JSON_ENV = "VERTEX_SERVICE_ACCOUNT_JSON";
|
|
300679
300997
|
var GOOGLE_APPLICATION_CREDENTIALS_ENV = "GOOGLE_APPLICATION_CREDENTIALS";
|
|
300680
300998
|
var GOOGLE_CLOUD_PROJECT_ENV = "GOOGLE_CLOUD_PROJECT";
|
|
@@ -300698,7 +301016,7 @@ function readProjectIdFromVertexServiceAccountJson() {
|
|
|
300698
301016
|
}
|
|
300699
301017
|
function createSecretDir() {
|
|
300700
301018
|
const base = process.env.INFRAWEAVER_SECRET_HOME || process.env.HOME || homedir();
|
|
300701
|
-
const secretDir =
|
|
301019
|
+
const secretDir = join60(base, `.${PRODUCT_SLUG}`, "secrets", randomUUID9());
|
|
300702
301020
|
mkdirSync8(secretDir, { recursive: true, mode: 448 });
|
|
300703
301021
|
return secretDir;
|
|
300704
301022
|
}
|
|
@@ -300707,7 +301025,7 @@ function materializeVertexCredentials(params) {
|
|
|
300707
301025
|
const blob = process.env[VERTEX_SERVICE_ACCOUNT_JSON_ENV];
|
|
300708
301026
|
if (!blob) return void 0;
|
|
300709
301027
|
const secretDir = createSecretDir();
|
|
300710
|
-
const credentialsPath =
|
|
301028
|
+
const credentialsPath = join60(secretDir, "vertex-sa.json");
|
|
300711
301029
|
writeFileSync18(credentialsPath, blob, { mode: 384 });
|
|
300712
301030
|
process.env[GOOGLE_APPLICATION_CREDENTIALS_ENV] = credentialsPath;
|
|
300713
301031
|
const projectId = readProjectIdFromVertexServiceAccountJson();
|
|
@@ -300843,29 +301161,29 @@ function createProcessOutputActivityTimeout(ctx) {
|
|
|
300843
301161
|
}
|
|
300844
301162
|
|
|
300845
301163
|
// src/utils/prompt/skills.ts
|
|
300846
|
-
import { existsSync as
|
|
300847
|
-
import { dirname as dirname9, join as
|
|
301164
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync36, writeFileSync as writeFileSync19 } from "node:fs";
|
|
301165
|
+
import { dirname as dirname9, join as join61 } from "node:path";
|
|
300848
301166
|
import { fileURLToPath } from "node:url";
|
|
300849
301167
|
var BUNDLED_SKILL_NAMES = ["terraform-best-practices"];
|
|
300850
301168
|
function resolveSkillPath(name) {
|
|
300851
301169
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
300852
301170
|
const candidates = [
|
|
300853
|
-
|
|
300854
|
-
|
|
301171
|
+
join61(here, "..", "..", "skills", name, "SKILL.md"),
|
|
301172
|
+
join61(here, "skills", name, "SKILL.md")
|
|
300855
301173
|
];
|
|
300856
301174
|
for (const candidate of candidates) {
|
|
300857
|
-
if (
|
|
301175
|
+
if (existsSync15(candidate)) return candidate;
|
|
300858
301176
|
}
|
|
300859
301177
|
throw new Error(`bundled skill not found: ${name} (looked in ${candidates.join(", ")})`);
|
|
300860
301178
|
}
|
|
300861
301179
|
var SKILL_TARGET_DIRS = [".opencode/skills", ".claude/skills", ".agents/skills"];
|
|
300862
301180
|
function installBundledSkills(params) {
|
|
300863
301181
|
for (const name of BUNDLED_SKILL_NAMES) {
|
|
300864
|
-
const content =
|
|
301182
|
+
const content = readFileSync36(resolveSkillPath(name), "utf8");
|
|
300865
301183
|
for (const targetDir of SKILL_TARGET_DIRS) {
|
|
300866
|
-
const skillDir =
|
|
301184
|
+
const skillDir = join61(params.home, targetDir, name);
|
|
300867
301185
|
mkdirSync9(skillDir, { recursive: true });
|
|
300868
|
-
writeFileSync19(
|
|
301186
|
+
writeFileSync19(join61(skillDir, "SKILL.md"), content);
|
|
300869
301187
|
}
|
|
300870
301188
|
}
|
|
300871
301189
|
log2.success(`installed bundled skills: ${BUNDLED_SKILL_NAMES.join(", ")}`);
|
|
@@ -300874,8 +301192,8 @@ function installBundledSkills(params) {
|
|
|
300874
301192
|
// src/utils/setup/install.ts
|
|
300875
301193
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
300876
301194
|
import { createHash as createHash14 } from "node:crypto";
|
|
300877
|
-
import { chmodSync as chmodSync2, createWriteStream as createWriteStream2, existsSync as
|
|
300878
|
-
import { join as
|
|
301195
|
+
import { chmodSync as chmodSync2, createWriteStream as createWriteStream2, existsSync as existsSync18, readFileSync as readFileSync37 } from "node:fs";
|
|
301196
|
+
import { join as join66 } from "node:path";
|
|
300879
301197
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
300880
301198
|
|
|
300881
301199
|
// src/utils/setup/tarballCache.ts
|
|
@@ -300930,7 +301248,7 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
300930
301248
|
`Refusing to install ${descriptor}: the registry published no integrity digest (neither dist.integrity nor dist.shasum), so the download cannot be verified.`
|
|
300931
301249
|
);
|
|
300932
301250
|
}
|
|
300933
|
-
const bytes =
|
|
301251
|
+
const bytes = readFileSync37(tarballPath);
|
|
300934
301252
|
if (integrity2) {
|
|
300935
301253
|
const candidates = integrity2.trim().split(/\s+/).filter(Boolean);
|
|
300936
301254
|
for (const candidate of candidates) {
|
|
@@ -300959,9 +301277,9 @@ function verifyTarballIntegrity(tarballPath, dist, descriptor) {
|
|
|
300959
301277
|
}
|
|
300960
301278
|
async function installFromNpmTarball(params) {
|
|
300961
301279
|
const tempDir = getTempDir();
|
|
300962
|
-
const extractedDir =
|
|
300963
|
-
const cliPath =
|
|
300964
|
-
if (
|
|
301280
|
+
const extractedDir = join66(tempDir, "package");
|
|
301281
|
+
const cliPath = join66(extractedDir, params.executablePath);
|
|
301282
|
+
if (existsSync18(cliPath)) {
|
|
300965
301283
|
log2.debug(`\xBB using cached binary at ${cliPath}`);
|
|
300966
301284
|
return cliPath;
|
|
300967
301285
|
}
|
|
@@ -301012,7 +301330,7 @@ async function installFromNpmTarball(params) {
|
|
|
301012
301330
|
dist = (await manifestResponse.json()).dist;
|
|
301013
301331
|
}
|
|
301014
301332
|
log2.debug(`\xBB installing ${params.packageName}@${resolvedVersion}...`);
|
|
301015
|
-
const tarballPath =
|
|
301333
|
+
const tarballPath = join66(tempDir, "package.tgz");
|
|
301016
301334
|
const tarballFileName = params.packageName.startsWith("@") ? params.packageName.split("/")[1] : params.packageName;
|
|
301017
301335
|
const tarballUrl = `${npmRegistry}/${encodedName}/-/${tarballFileName}-${resolvedVersion}.tgz`;
|
|
301018
301336
|
const restored = await restoreTarball({
|
|
@@ -301052,7 +301370,7 @@ async function installFromNpmTarball(params) {
|
|
|
301052
301370
|
`Failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "Unknown error"}`
|
|
301053
301371
|
);
|
|
301054
301372
|
}
|
|
301055
|
-
if (!
|
|
301373
|
+
if (!existsSync18(cliPath)) {
|
|
301056
301374
|
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
|
301057
301375
|
}
|
|
301058
301376
|
if (params.installDependencies) {
|
|
@@ -301163,9 +301481,9 @@ var CLAUDE_DISALLOWED_TOOLS = CLAUDE_EXEC_TOOL_DENY_RULES.join(",");
|
|
|
301163
301481
|
var INFRAWEAVER_MCP_AUTH_HEADER = `Bearer \${${MCP_SERVER_TOKEN_ENV}}`;
|
|
301164
301482
|
var CLAUDE_MAX_CONCURRENT_SUBAGENTS_DEFAULT = "4";
|
|
301165
301483
|
function writeMcpConfig(ctx) {
|
|
301166
|
-
const configDir =
|
|
301484
|
+
const configDir = join67(ctx.tmpdir, ".claude");
|
|
301167
301485
|
mkdirSync10(configDir, { recursive: true });
|
|
301168
|
-
const configPath =
|
|
301486
|
+
const configPath = join67(configDir, "mcp.json");
|
|
301169
301487
|
const terraformMcp = resolveTerraformMcp(ctx.payload);
|
|
301170
301488
|
if (terraformMcp.kind === "docker_missing") log2.info(`\xBB ${terraformMcp.note}`);
|
|
301171
301489
|
const opentofuMcp = resolveOpenTofuMcp(ctx.payload);
|
|
@@ -301197,13 +301515,13 @@ function writeMcpConfig(ctx) {
|
|
|
301197
301515
|
return configPath;
|
|
301198
301516
|
}
|
|
301199
301517
|
function writePretoolGateAssets(ctx, stopHookPath) {
|
|
301200
|
-
const scriptPath =
|
|
301518
|
+
const scriptPath = join67(ctx.tmpdir, CLAUDE_PRETOOL_GATE_FILENAME);
|
|
301201
301519
|
writeFileSync22(
|
|
301202
301520
|
scriptPath,
|
|
301203
301521
|
buildClaudePretoolGateSource(ctx.subagentDeniedTools, writePolicyPath2(ctx.tmpdir))
|
|
301204
301522
|
);
|
|
301205
301523
|
chmodSync3(scriptPath, 493);
|
|
301206
|
-
const settingsPath =
|
|
301524
|
+
const settingsPath = join67(ctx.tmpdir, "infraweaver-claude-settings.json");
|
|
301207
301525
|
const settings = buildClaudePretoolGateSettings(scriptPath, CLAUDE_EXEC_TOOL_DENY_RULES);
|
|
301208
301526
|
settings.permissions.deny.push(...harnessTmpdirWriteDenyClaude(ctx.tmpdir));
|
|
301209
301527
|
if (stopHookPath) {
|
|
@@ -301292,7 +301610,7 @@ function timerFor(state5, label) {
|
|
|
301292
301610
|
function chargeTokenQuota(state5) {
|
|
301293
301611
|
const quota = state5.params.tokenQuota;
|
|
301294
301612
|
if (!quota || state5.stopRun.signal.aborted) return;
|
|
301295
|
-
if (!quota.observe(state5.quotaSource, state5.accumulatedTokens)) return;
|
|
301613
|
+
if (!quota.observe(state5.quotaSource, quotaTokens(state5.accumulatedTokens))) return;
|
|
301296
301614
|
log2.info(`\xBB ${state5.params.label}: ${quota.gap()}`);
|
|
301297
301615
|
state5.stopRun.abort(new TokenQuotaExceededError(quota.gap()));
|
|
301298
301616
|
}
|
|
@@ -301828,11 +302146,11 @@ var claude = agent({
|
|
|
301828
302146
|
const onVertex = matchesRouteSentinel(VERTEX_MODEL_ID_ENV, specifier) && specifier !== void 0 && isVertexAnthropicId(specifier);
|
|
301829
302147
|
const model = !specifier ? void 0 : onBedrock ? specifier : onVertex ? void 0 : stripProviderPrefix(specifier);
|
|
301830
302148
|
const homeEnv = agentHomeEnv(ctx.tmpdir);
|
|
301831
|
-
mkdirSync10(
|
|
302149
|
+
mkdirSync10(join67(homeEnv.XDG_CONFIG_HOME, "claude"), { recursive: true });
|
|
301832
302150
|
installBundledSkills({ home: homeEnv.HOME });
|
|
301833
302151
|
const mcpConfigPath = writeMcpConfig(ctx);
|
|
301834
302152
|
const effort = resolveEffort(model);
|
|
301835
|
-
const stopHookPath =
|
|
302153
|
+
const stopHookPath = join67(ctx.tmpdir, "infraweaver-stop-hook.sh");
|
|
301836
302154
|
writeFileSync22(stopHookPath, buildStopHookScript(), { mode: 493 });
|
|
301837
302155
|
const pretoolGate = writePretoolGateAssets(ctx, stopHookPath);
|
|
301838
302156
|
installManagedSettings({
|
|
@@ -301998,7 +302316,7 @@ var claude = agent({
|
|
|
301998
302316
|
init_core3();
|
|
301999
302317
|
import { spawn as nodeSpawn2 } from "node:child_process";
|
|
302000
302318
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync24 } from "node:fs";
|
|
302001
|
-
import { join as
|
|
302319
|
+
import { join as join69 } from "node:path";
|
|
302002
302320
|
import { performance as performance7 } from "node:perf_hooks";
|
|
302003
302321
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
302004
302322
|
import { setTimeout as sleep7 } from "node:timers/promises";
|
|
@@ -307681,7 +307999,7 @@ function autoSelectModel() {
|
|
|
307681
307999
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
307682
308000
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync23 } from "node:fs";
|
|
307683
308001
|
import { homedir as homedir3, userInfo as userInfo2 } from "node:os";
|
|
307684
|
-
import { join as
|
|
308002
|
+
import { join as join68 } from "node:path";
|
|
307685
308003
|
|
|
307686
308004
|
// src/utils/agent/codexOAuth.ts
|
|
307687
308005
|
init_webapi();
|
|
@@ -307735,8 +308053,8 @@ function installCodexAuth() {
|
|
|
307735
308053
|
}
|
|
307736
308054
|
const expiresMs = decodeJwtExpMs(body2.tokens.access_token) ?? 0;
|
|
307737
308055
|
const xdgDataHome = resolveDataHome();
|
|
307738
|
-
const opencodeDir =
|
|
307739
|
-
const authPath =
|
|
308056
|
+
const opencodeDir = join68(xdgDataHome, "opencode");
|
|
308057
|
+
const authPath = join68(opencodeDir, "auth.json");
|
|
307740
308058
|
const opencodeAuth = {
|
|
307741
308059
|
openai: {
|
|
307742
308060
|
type: "oauth",
|
|
@@ -307760,7 +308078,7 @@ function installCodexAuth() {
|
|
|
307760
308078
|
};
|
|
307761
308079
|
}
|
|
307762
308080
|
function resolveDataHome() {
|
|
307763
|
-
if (process.env.CI !== "true") return
|
|
308081
|
+
if (process.env.CI !== "true") return join68(homedir3(), ".local", "share");
|
|
307764
308082
|
bootstrapInfraweaverDataDir();
|
|
307765
308083
|
return INFRAWEAVER_DATA_DIR;
|
|
307766
308084
|
}
|
|
@@ -308034,7 +308352,7 @@ function newTurn() {
|
|
|
308034
308352
|
function chargeTokenQuota2(ctx) {
|
|
308035
308353
|
const quota = ctx.tokenQuota;
|
|
308036
308354
|
if (!quota || !ctx.currentTurn || ctx.tokenQuotaExceeded) return;
|
|
308037
|
-
if (!quota.observe(ctx.currentTurn.quotaSource, ctx.currentTurn.tokens)) return;
|
|
308355
|
+
if (!quota.observe(ctx.currentTurn.quotaSource, quotaTokens(ctx.currentTurn.tokens))) return;
|
|
308038
308356
|
ctx.tokenQuotaExceeded = true;
|
|
308039
308357
|
log2.info(`\xBB ${ctx.label}: ${quota.gap()}`);
|
|
308040
308358
|
ctx.abortRun?.(new TokenQuotaExceededError(quota.gap()));
|
|
@@ -308501,10 +308819,10 @@ var opencode = agent({
|
|
|
308501
308819
|
const openAiCompatModel = resolveOpenAiCompatibleOpenCodeModel(rawModel);
|
|
308502
308820
|
const model = isBedrockRoute ? `amazon-bedrock/${rawModel}` : vertexModel ?? openAiCompatModel ?? rawModel;
|
|
308503
308821
|
const homeEnv = agentHomeEnv(ctx.tmpdir);
|
|
308504
|
-
const opencodePluginDir =
|
|
308822
|
+
const opencodePluginDir = join69(homeEnv.XDG_CONFIG_HOME, "opencode", "plugin");
|
|
308505
308823
|
mkdirSync12(opencodePluginDir, { recursive: true });
|
|
308506
308824
|
writeFileSync24(
|
|
308507
|
-
|
|
308825
|
+
join69(opencodePluginDir, INFRAWEAVER_OPENCODE_GATE_PLUGIN_FILENAME),
|
|
308508
308826
|
buildOpencodeSubagentGateSource(ctx.subagentDeniedTools, writePolicyPath2(ctx.tmpdir))
|
|
308509
308827
|
);
|
|
308510
308828
|
installBundledSkills({ home: homeEnv.HOME });
|
|
@@ -309540,7 +309858,7 @@ async function fetchRunContext(params) {
|
|
|
309540
309858
|
// src/utils/github/github.ts
|
|
309541
309859
|
init_core3();
|
|
309542
309860
|
import { rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
309543
|
-
import { dirname as dirname12, join as
|
|
309861
|
+
import { dirname as dirname12, join as join70 } from "node:path";
|
|
309544
309862
|
|
|
309545
309863
|
// node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
|
|
309546
309864
|
function getUserAgent2() {
|
|
@@ -315356,7 +315674,7 @@ function getGitHubUsageSummary() {
|
|
|
315356
315674
|
}
|
|
315357
315675
|
async function writeGitHubUsageSummaryToFile(path15) {
|
|
315358
315676
|
const summary2 = getGitHubUsageSummary();
|
|
315359
|
-
const tmpPath =
|
|
315677
|
+
const tmpPath = join70(dirname12(path15), `.usage-summary-${process.pid}.tmp`);
|
|
315360
315678
|
await writeFile2(tmpPath, JSON.stringify(summary2));
|
|
315361
315679
|
await rename2(tmpPath, path15);
|
|
315362
315680
|
}
|
|
@@ -315901,7 +316219,7 @@ async function resolveModelAndAuth(params) {
|
|
|
315901
316219
|
// src/utils/run/runLifecycle.ts
|
|
315902
316220
|
init_core3();
|
|
315903
316221
|
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
315904
|
-
import { join as
|
|
316222
|
+
import { join as join73, resolve as resolve10 } from "node:path";
|
|
315905
316223
|
|
|
315906
316224
|
// src/utils/cloud/cloudReport.ts
|
|
315907
316225
|
init_core3();
|
|
@@ -316295,7 +316613,7 @@ async function reportToCloud(input2) {
|
|
|
316295
316613
|
|
|
316296
316614
|
// src/utils/cloud/learnings.ts
|
|
316297
316615
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
316298
|
-
import { dirname as dirname13, join as
|
|
316616
|
+
import { dirname as dirname13, join as join71 } from "node:path";
|
|
316299
316617
|
|
|
316300
316618
|
// src/utils/cloud/learningsTruncate.ts
|
|
316301
316619
|
var MAX_LEARNINGS_LENGTH = 1e5;
|
|
@@ -316312,7 +316630,7 @@ function truncateAtLineBoundary(body2, cap2) {
|
|
|
316312
316630
|
// src/utils/cloud/learnings.ts
|
|
316313
316631
|
var LEARNINGS_FILE_NAME = LEARNINGS_FILE;
|
|
316314
316632
|
function learningsFilePath(tmpdir5) {
|
|
316315
|
-
return
|
|
316633
|
+
return join71(tmpdir5, LEARNINGS_FILE_NAME);
|
|
316316
316634
|
}
|
|
316317
316635
|
async function seedLearningsFile(params) {
|
|
316318
316636
|
const path15 = learningsFilePath(params.tmpdir);
|
|
@@ -316443,7 +316761,7 @@ ${ctx.error}` : ctx.error;
|
|
|
316443
316761
|
|
|
316444
316762
|
// src/utils/github/prSummary.ts
|
|
316445
316763
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
|
|
316446
|
-
import { dirname as dirname14, join as
|
|
316764
|
+
import { dirname as dirname14, join as join72 } from "node:path";
|
|
316447
316765
|
var SUMMARY_FILE_NAME = SUMMARY_FILE;
|
|
316448
316766
|
var SUMMARY_SCAFFOLD = `# PR summary
|
|
316449
316767
|
|
|
@@ -316453,7 +316771,7 @@ var SUMMARY_SCAFFOLD = `# PR summary
|
|
|
316453
316771
|
var MIN_SNAPSHOT_LENGTH = 60;
|
|
316454
316772
|
var MAX_SNAPSHOT_LENGTH = 32768;
|
|
316455
316773
|
function summaryFilePath(tmpdir5) {
|
|
316456
|
-
return
|
|
316774
|
+
return join72(tmpdir5, SUMMARY_FILE_NAME);
|
|
316457
316775
|
}
|
|
316458
316776
|
async function seedSummaryFile(params) {
|
|
316459
316777
|
const path15 = summaryFilePath(params.tmpdir);
|
|
@@ -316987,7 +317305,7 @@ async function emitFindingsOutputs(toolState, requiredControls) {
|
|
|
316987
317305
|
if (a.level === "error") error62(a.message, props);
|
|
316988
317306
|
else warning(a.message, props);
|
|
316989
317307
|
}
|
|
316990
|
-
const sarifPath =
|
|
317308
|
+
const sarifPath = join73(workspace, SARIF_FILE);
|
|
316991
317309
|
if (session.emittedSarifPath && resolve10(session.emittedSarifPath) === resolve10(sarifPath)) {
|
|
316992
317310
|
log2.info(`\xBB findings output: replacing the agent-emitted ${SARIF_FILE} with the gate's`);
|
|
316993
317311
|
}
|
|
@@ -317417,9 +317735,9 @@ async function runAgentWithWatchdogs(params) {
|
|
|
317417
317735
|
}
|
|
317418
317736
|
|
|
317419
317737
|
// src/phases/startToolPlane.ts
|
|
317420
|
-
import { existsSync as
|
|
317738
|
+
import { existsSync as existsSync19, readdirSync as readdirSync10 } from "node:fs";
|
|
317421
317739
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
317422
|
-
import { join as
|
|
317740
|
+
import { join as join74 } from "node:path";
|
|
317423
317741
|
|
|
317424
317742
|
// src/utils/cloud/runTerminalStatus.ts
|
|
317425
317743
|
var TERMINAL_STATE_KEY = "run_terminal";
|
|
@@ -318247,8 +318565,8 @@ ${instructions.user}` : null,
|
|
|
318247
318565
|
log2.info(instructions.full);
|
|
318248
318566
|
});
|
|
318249
318567
|
if (toolContext.agentId === "opencode") {
|
|
318250
|
-
const pluginDir =
|
|
318251
|
-
const hasPlugins =
|
|
318568
|
+
const pluginDir = join74(process.cwd(), ".opencode", "plugin");
|
|
318569
|
+
const hasPlugins = existsSync19(pluginDir) && readdirSync10(pluginDir).some((f) => /\.[jt]sx?$/.test(f));
|
|
318252
318570
|
if (hasPlugins && toolState.dependencyInstallation?.promise) {
|
|
318253
318571
|
log2.info(
|
|
318254
318572
|
"\xBB .opencode/plugin/ detected \u2014 awaiting dependency installation before agent start"
|