diff --git a/.changeset/patch-refactor-mcp-server-utilities.md b/.changeset/patch-refactor-mcp-server-utilities.md
new file mode 100644
index 00000000000..1ae877bee38
--- /dev/null
+++ b/.changeset/patch-refactor-mcp-server-utilities.md
@@ -0,0 +1,7 @@
+---
+"gh-aw": patch
+---
+
+Refactor safe_outputs_mcp_server.cjs: Extract utility functions with bundling and size logging
+
+Extracted 7 utility functions from the monolithic safe_outputs_mcp_server.cjs file into separate, well-tested modules with automatic bundling. Added 50 comprehensive unit tests, detailed size logging during bundling, and fixed MCP server script generation bug. All functionality preserved with no breaking changes.
diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml
index f92613a8f85..c2ebd4902e0 100644
--- a/.github/workflows/ai-triage-campaign.lock.yml
+++ b/.github/workflows/ai-triage-campaign.lock.yml
@@ -519,9 +519,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -536,6 +533,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -636,51 +792,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -800,156 +911,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml
index c0682c378a5..27383711776 100644
--- a/.github/workflows/archie.lock.yml
+++ b/.github/workflows/archie.lock.yml
@@ -1532,9 +1532,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1549,6 +1546,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1649,51 +1805,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1813,156 +1924,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml
index e5a943001a2..34bda1e9536 100644
--- a/.github/workflows/artifacts-summary.lock.yml
+++ b/.github/workflows/artifacts-summary.lock.yml
@@ -453,9 +453,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -470,6 +467,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -570,51 +726,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -734,156 +845,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml
index 3107833629e..a2acda06079 100644
--- a/.github/workflows/audit-workflows.lock.yml
+++ b/.github/workflows/audit-workflows.lock.yml
@@ -1214,9 +1214,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1231,6 +1228,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1331,51 +1487,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1495,156 +1606,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml
index 388f4152e2d..601a054e83b 100644
--- a/.github/workflows/blog-auditor.lock.yml
+++ b/.github/workflows/blog-auditor.lock.yml
@@ -735,9 +735,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -752,6 +749,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -852,51 +1008,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1016,156 +1127,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml
index 4913e6c5db6..ca15cf73457 100644
--- a/.github/workflows/brave.lock.yml
+++ b/.github/workflows/brave.lock.yml
@@ -1424,9 +1424,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1441,6 +1438,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1541,51 +1697,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1705,156 +1816,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml
index a68de360534..f97bfae82b6 100644
--- a/.github/workflows/changeset.lock.yml
+++ b/.github/workflows/changeset.lock.yml
@@ -1168,9 +1168,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1185,6 +1182,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1285,51 +1441,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1449,156 +1560,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
index 9f49955bbdc..6c9d8fdad4b 100644
--- a/.github/workflows/ci-doctor.lock.yml
+++ b/.github/workflows/ci-doctor.lock.yml
@@ -899,9 +899,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -916,6 +913,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1016,51 +1172,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1180,156 +1291,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml
index bbdcf3871a7..baa1bffdd0c 100644
--- a/.github/workflows/cli-consistency-checker.lock.yml
+++ b/.github/workflows/cli-consistency-checker.lock.yml
@@ -464,9 +464,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -481,6 +478,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -581,51 +737,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -745,156 +856,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml
index 69b75f87a75..12b10d0cb8d 100644
--- a/.github/workflows/cli-version-checker.lock.yml
+++ b/.github/workflows/cli-version-checker.lock.yml
@@ -629,9 +629,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -646,6 +643,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -746,51 +902,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -910,156 +1021,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml
index 2b1f563d4e0..8a97d4596fa 100644
--- a/.github/workflows/cloclo.lock.yml
+++ b/.github/workflows/cloclo.lock.yml
@@ -1773,9 +1773,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1790,6 +1787,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1890,51 +2046,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -2054,156 +2165,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml
index d3266e3c468..9bec573c6e3 100644
--- a/.github/workflows/commit-changes-analyzer.lock.yml
+++ b/.github/workflows/commit-changes-analyzer.lock.yml
@@ -706,9 +706,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -723,6 +720,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -823,51 +979,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -987,156 +1098,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml
index 1efa5a16702..e1ab252bf0a 100644
--- a/.github/workflows/copilot-agent-analysis.lock.yml
+++ b/.github/workflows/copilot-agent-analysis.lock.yml
@@ -1111,9 +1111,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1128,6 +1125,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1228,51 +1384,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1392,156 +1503,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
index 8685f55a3d3..34057f3b57e 100644
--- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
@@ -1261,9 +1261,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1278,6 +1275,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1378,51 +1534,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1542,156 +1653,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
index 40a5a56c517..3370b6ce47d 100644
--- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
@@ -834,9 +834,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -851,6 +848,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -951,51 +1107,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1115,156 +1226,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml
index 5f10a2b1d24..c355ae72411 100644
--- a/.github/workflows/copilot-session-insights.lock.yml
+++ b/.github/workflows/copilot-session-insights.lock.yml
@@ -1944,9 +1944,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1961,6 +1958,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -2061,51 +2217,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -2225,156 +2336,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml
index 4b2226ffd0e..917590c0870 100644
--- a/.github/workflows/craft.lock.yml
+++ b/.github/workflows/craft.lock.yml
@@ -1577,9 +1577,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1594,6 +1591,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1694,51 +1850,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1858,156 +1969,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml
index 91cd4921681..b66b8ad0f09 100644
--- a/.github/workflows/daily-code-metrics.lock.yml
+++ b/.github/workflows/daily-code-metrics.lock.yml
@@ -1289,9 +1289,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1306,6 +1303,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1406,51 +1562,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1570,156 +1681,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml
index a8e0518384a..5365fa6d859 100644
--- a/.github/workflows/daily-doc-updater.lock.yml
+++ b/.github/workflows/daily-doc-updater.lock.yml
@@ -576,9 +576,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -593,6 +590,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -693,51 +849,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -857,156 +968,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml
index e5be2a75133..faea0e55fe4 100644
--- a/.github/workflows/daily-file-diet.lock.yml
+++ b/.github/workflows/daily-file-diet.lock.yml
@@ -619,9 +619,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -636,6 +633,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -736,51 +892,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -900,156 +1011,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml
index 6a6253a6d52..86b765f9d93 100644
--- a/.github/workflows/daily-firewall-report.lock.yml
+++ b/.github/workflows/daily-firewall-report.lock.yml
@@ -962,9 +962,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -979,6 +976,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1079,51 +1235,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1243,156 +1354,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml
index 564680acdf1..7a8b7ad4c5a 100644
--- a/.github/workflows/daily-malicious-code-scan.lock.yml
+++ b/.github/workflows/daily-malicious-code-scan.lock.yml
@@ -569,9 +569,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -586,6 +583,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -686,51 +842,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -850,156 +961,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml
index 927e1486837..8f494889b79 100644
--- a/.github/workflows/daily-multi-device-docs-tester.lock.yml
+++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml
@@ -498,9 +498,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -515,6 +512,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -615,51 +771,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -779,156 +890,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml
index a65960b3488..f889f21cc57 100644
--- a/.github/workflows/daily-news.lock.yml
+++ b/.github/workflows/daily-news.lock.yml
@@ -1137,9 +1137,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1154,6 +1151,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1254,51 +1410,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1418,156 +1529,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml
index 5139e0a30f1..c8f08f53a48 100644
--- a/.github/workflows/daily-repo-chronicle.lock.yml
+++ b/.github/workflows/daily-repo-chronicle.lock.yml
@@ -1007,9 +1007,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1024,6 +1021,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1124,51 +1280,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1288,156 +1399,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml
index 232a82ac011..ce3c29d0d75 100644
--- a/.github/workflows/daily-team-status.lock.yml
+++ b/.github/workflows/daily-team-status.lock.yml
@@ -398,9 +398,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -415,6 +412,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -515,51 +671,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -679,156 +790,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
@@ -1350,6 +1311,9 @@ jobs:
{{#if ${{ github.repository }} }}
- **Repository**: `${{ github.repository }}`
{{/if}}
+ {{#if ${{ github.workspace }} }}
+ - **Workspace**: `${{ github.workspace }}`
+ {{/if}}
{{#if ${{ github.event.issue.number }} }}
- **Issue Number**: `#${{ github.event.issue.number }}`
{{/if}}
diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml
index 25ea2c6df44..9e0e4316470 100644
--- a/.github/workflows/dependabot-go-checker.lock.yml
+++ b/.github/workflows/dependabot-go-checker.lock.yml
@@ -711,9 +711,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -728,6 +725,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -828,51 +984,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -992,156 +1103,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml
index f76977641a8..d5473c596fd 100644
--- a/.github/workflows/dev-hawk.lock.yml
+++ b/.github/workflows/dev-hawk.lock.yml
@@ -820,9 +820,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -837,6 +834,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -937,51 +1093,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1101,156 +1212,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml
index e71e3433b12..e2387b45520 100644
--- a/.github/workflows/dev.lock.yml
+++ b/.github/workflows/dev.lock.yml
@@ -318,9 +318,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -335,6 +332,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -435,51 +591,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -599,156 +710,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml
index f159f315013..e6440be4866 100644
--- a/.github/workflows/developer-docs-consolidator.lock.yml
+++ b/.github/workflows/developer-docs-consolidator.lock.yml
@@ -1092,9 +1092,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1109,6 +1106,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1209,51 +1365,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1373,156 +1484,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml
index f1da4c1f15c..192fb78c1d9 100644
--- a/.github/workflows/dictation-prompt.lock.yml
+++ b/.github/workflows/dictation-prompt.lock.yml
@@ -435,9 +435,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -452,6 +449,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -552,51 +708,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -716,156 +827,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml
index 1ad2b04ec8f..3abca15b999 100644
--- a/.github/workflows/docs-noob-tester.lock.yml
+++ b/.github/workflows/docs-noob-tester.lock.yml
@@ -459,9 +459,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -476,6 +473,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -576,51 +732,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -740,156 +851,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml
index 3a4f4866400..2166c052f31 100644
--- a/.github/workflows/duplicate-code-detector.lock.yml
+++ b/.github/workflows/duplicate-code-detector.lock.yml
@@ -523,9 +523,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -540,6 +537,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -640,51 +796,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -804,156 +915,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml
index 3dc7f5a1011..40817353d0d 100644
--- a/.github/workflows/example-workflow-analyzer.lock.yml
+++ b/.github/workflows/example-workflow-analyzer.lock.yml
@@ -510,9 +510,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -527,6 +524,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -627,51 +783,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -791,156 +902,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml
index cf3b0652ea9..f2f442aad97 100644
--- a/.github/workflows/github-mcp-tools-report.lock.yml
+++ b/.github/workflows/github-mcp-tools-report.lock.yml
@@ -956,9 +956,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -973,6 +970,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1073,51 +1229,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1237,156 +1348,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml
index 4227f4d3dee..c5f9b4ee1e1 100644
--- a/.github/workflows/glossary-maintainer.lock.yml
+++ b/.github/workflows/glossary-maintainer.lock.yml
@@ -943,9 +943,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -960,6 +957,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1060,51 +1216,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1224,156 +1335,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml
index 5e8ba8cc815..6b1d6fdaf7e 100644
--- a/.github/workflows/go-logger.lock.yml
+++ b/.github/workflows/go-logger.lock.yml
@@ -692,9 +692,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -709,6 +706,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -809,51 +965,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -973,156 +1084,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml
index 3928678e485..9ed64226a2f 100644
--- a/.github/workflows/go-pattern-detector.lock.yml
+++ b/.github/workflows/go-pattern-detector.lock.yml
@@ -540,9 +540,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -557,6 +554,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -657,51 +813,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -821,156 +932,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml
index edbbb3996db..d393b9505de 100644
--- a/.github/workflows/grumpy-reviewer.lock.yml
+++ b/.github/workflows/grumpy-reviewer.lock.yml
@@ -1472,9 +1472,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1489,6 +1486,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1589,51 +1745,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1753,156 +1864,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml
index edea14cefcd..f32e21a7c20 100644
--- a/.github/workflows/instructions-janitor.lock.yml
+++ b/.github/workflows/instructions-janitor.lock.yml
@@ -575,9 +575,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -592,6 +589,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -692,51 +848,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -856,156 +967,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml
index 91bc9d1dcf9..d38e340237b 100644
--- a/.github/workflows/issue-classifier.lock.yml
+++ b/.github/workflows/issue-classifier.lock.yml
@@ -1379,9 +1379,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1396,6 +1393,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1496,51 +1652,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1660,156 +1771,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml
index c90b89ff76f..c91e11c81d3 100644
--- a/.github/workflows/lockfile-stats.lock.yml
+++ b/.github/workflows/lockfile-stats.lock.yml
@@ -828,9 +828,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -845,6 +842,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -945,51 +1101,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1109,156 +1220,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml
index a72d308dcb9..d84934595d4 100644
--- a/.github/workflows/mcp-inspector.lock.yml
+++ b/.github/workflows/mcp-inspector.lock.yml
@@ -950,9 +950,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -967,6 +964,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1067,51 +1223,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1231,156 +1342,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml
index 0fccbb18dce..d1a8be06482 100644
--- a/.github/workflows/mergefest.lock.yml
+++ b/.github/workflows/mergefest.lock.yml
@@ -922,9 +922,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -939,6 +936,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1039,51 +1195,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1203,156 +1314,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml
index 82febab9fad..188a4625c59 100644
--- a/.github/workflows/notion-issue-summary.lock.yml
+++ b/.github/workflows/notion-issue-summary.lock.yml
@@ -319,9 +319,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -336,6 +333,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -436,51 +592,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -600,156 +711,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml
index a22e5932c03..32d0f16bfa6 100644
--- a/.github/workflows/pdf-summary.lock.yml
+++ b/.github/workflows/pdf-summary.lock.yml
@@ -1513,9 +1513,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1530,6 +1527,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1630,51 +1786,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1794,156 +1905,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml
index ef25ba12b84..0653acbd8ff 100644
--- a/.github/workflows/plan.lock.yml
+++ b/.github/workflows/plan.lock.yml
@@ -1034,9 +1034,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1051,6 +1048,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1151,51 +1307,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1315,156 +1426,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml
index 2dc5f841d97..3fffece812b 100644
--- a/.github/workflows/poem-bot.lock.yml
+++ b/.github/workflows/poem-bot.lock.yml
@@ -1869,9 +1869,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1886,6 +1883,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1986,51 +2142,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -2150,156 +2261,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml
index c4d5d04b173..553eb368aa5 100644
--- a/.github/workflows/pr-nitpick-reviewer.lock.yml
+++ b/.github/workflows/pr-nitpick-reviewer.lock.yml
@@ -1530,9 +1530,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1547,6 +1544,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1647,51 +1803,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1811,156 +1922,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml
index a9ae7297e91..3cd23dd7c2b 100644
--- a/.github/workflows/prompt-clustering-analysis.lock.yml
+++ b/.github/workflows/prompt-clustering-analysis.lock.yml
@@ -1505,9 +1505,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1522,6 +1519,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1622,51 +1778,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1786,156 +1897,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml
index 8dfdaeb0f13..0f07795eae3 100644
--- a/.github/workflows/python-data-charts.lock.yml
+++ b/.github/workflows/python-data-charts.lock.yml
@@ -1326,9 +1326,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1343,6 +1340,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1443,51 +1599,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1607,156 +1718,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml
index d97618283db..385a6451a42 100644
--- a/.github/workflows/q.lock.yml
+++ b/.github/workflows/q.lock.yml
@@ -1773,9 +1773,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1790,6 +1787,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1890,51 +2046,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -2054,156 +2165,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/release-highlights.lock.yml b/.github/workflows/release-highlights.lock.yml
index 81d5db0fd92..b560a5f4378 100644
--- a/.github/workflows/release-highlights.lock.yml
+++ b/.github/workflows/release-highlights.lock.yml
@@ -519,9 +519,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -536,6 +533,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -636,51 +792,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -800,156 +911,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml
index cb071930254..04897962529 100644
--- a/.github/workflows/repo-tree-map.lock.yml
+++ b/.github/workflows/repo-tree-map.lock.yml
@@ -479,9 +479,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -496,6 +493,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -596,51 +752,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -760,156 +871,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml
index f3c1e31a5f7..eba79f082a6 100644
--- a/.github/workflows/repository-quality-improver.lock.yml
+++ b/.github/workflows/repository-quality-improver.lock.yml
@@ -931,9 +931,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -948,6 +945,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1048,51 +1204,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1212,156 +1323,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml
index 01191a287a1..67a87eec351 100644
--- a/.github/workflows/research.lock.yml
+++ b/.github/workflows/research.lock.yml
@@ -403,9 +403,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -420,6 +417,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -520,51 +676,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -684,156 +795,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml
index 6b62ee8f03f..f534cebcc28 100644
--- a/.github/workflows/safe-output-health.lock.yml
+++ b/.github/workflows/safe-output-health.lock.yml
@@ -945,9 +945,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -962,6 +959,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1062,51 +1218,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1226,156 +1337,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml
index 855d231b015..c950e91e6ba 100644
--- a/.github/workflows/schema-consistency-checker.lock.yml
+++ b/.github/workflows/schema-consistency-checker.lock.yml
@@ -832,9 +832,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -849,6 +846,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -949,51 +1105,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1113,156 +1224,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml
index 29d773410ab..103d8cb4458 100644
--- a/.github/workflows/scout.lock.yml
+++ b/.github/workflows/scout.lock.yml
@@ -1864,9 +1864,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1881,6 +1878,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1981,51 +2137,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -2145,156 +2256,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml
index 896a58d37cd..700ec17d5a5 100644
--- a/.github/workflows/security-fix-pr.lock.yml
+++ b/.github/workflows/security-fix-pr.lock.yml
@@ -563,9 +563,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -580,6 +577,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -680,51 +836,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -844,156 +955,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml
index 4d9eaa224e6..e5a0fb4e6b7 100644
--- a/.github/workflows/semantic-function-refactor.lock.yml
+++ b/.github/workflows/semantic-function-refactor.lock.yml
@@ -908,9 +908,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -925,6 +922,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1025,51 +1181,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1189,156 +1300,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml
index b1bd45a01c8..9ae27e08d5b 100644
--- a/.github/workflows/smoke-claude.lock.yml
+++ b/.github/workflows/smoke-claude.lock.yml
@@ -966,9 +966,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -983,6 +980,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1083,51 +1239,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1247,156 +1358,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index d91acb04157..50ab507b3dc 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -742,9 +742,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -759,6 +756,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -859,51 +1015,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1023,156 +1134,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index 648c5a3cdd5..ad61c34b254 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -750,9 +750,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -767,6 +764,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -867,51 +1023,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1031,156 +1142,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml
index 03193627d64..1d3500d4547 100644
--- a/.github/workflows/smoke-detector.lock.yml
+++ b/.github/workflows/smoke-detector.lock.yml
@@ -1538,9 +1538,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1555,6 +1552,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1655,51 +1811,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1819,156 +1930,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml
index 098e410a91a..92660f0ff33 100644
--- a/.github/workflows/static-analysis-report.lock.yml
+++ b/.github/workflows/static-analysis-report.lock.yml
@@ -856,9 +856,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -873,6 +870,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -973,51 +1129,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1137,156 +1248,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml
index 6e4aaef2e22..e796789f738 100644
--- a/.github/workflows/super-linter.lock.yml
+++ b/.github/workflows/super-linter.lock.yml
@@ -517,9 +517,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -534,6 +531,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -634,51 +790,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -798,156 +909,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml
index c5378e72807..b079cf864d2 100644
--- a/.github/workflows/technical-doc-writer.lock.yml
+++ b/.github/workflows/technical-doc-writer.lock.yml
@@ -1161,9 +1161,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1178,6 +1175,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1278,51 +1434,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1442,156 +1553,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-assign-milestone-allowed.lock.yml b/.github/workflows/test-assign-milestone-allowed.lock.yml
index 03cfb3b20ab..d8311dab0c1 100644
--- a/.github/workflows/test-assign-milestone-allowed.lock.yml
+++ b/.github/workflows/test-assign-milestone-allowed.lock.yml
@@ -398,9 +398,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -415,6 +412,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -515,51 +671,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -679,156 +790,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-claude-assign-milestone.lock.yml b/.github/workflows/test-claude-assign-milestone.lock.yml
index 5a4c9d42abe..a74f72caf89 100644
--- a/.github/workflows/test-claude-assign-milestone.lock.yml
+++ b/.github/workflows/test-claude-assign-milestone.lock.yml
@@ -392,9 +392,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -409,6 +406,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -509,51 +665,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -673,156 +784,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-close-discussion.lock.yml b/.github/workflows/test-close-discussion.lock.yml
index 4a34058acbe..584e772c6ea 100644
--- a/.github/workflows/test-close-discussion.lock.yml
+++ b/.github/workflows/test-close-discussion.lock.yml
@@ -304,9 +304,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -321,6 +318,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -421,51 +577,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -585,156 +696,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-codex-assign-milestone.lock.yml b/.github/workflows/test-codex-assign-milestone.lock.yml
index 732ddfb4b9e..9b0677c63b1 100644
--- a/.github/workflows/test-codex-assign-milestone.lock.yml
+++ b/.github/workflows/test-codex-assign-milestone.lock.yml
@@ -283,9 +283,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -300,6 +297,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -400,51 +556,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -564,156 +675,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-copilot-assign-milestone.lock.yml b/.github/workflows/test-copilot-assign-milestone.lock.yml
index 4288cb93d14..7612d55b671 100644
--- a/.github/workflows/test-copilot-assign-milestone.lock.yml
+++ b/.github/workflows/test-copilot-assign-milestone.lock.yml
@@ -283,9 +283,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -300,6 +297,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -400,51 +556,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -564,156 +675,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml
index e47993ea80e..cc3beb3585a 100644
--- a/.github/workflows/test-ollama-threat-detection.lock.yml
+++ b/.github/workflows/test-ollama-threat-detection.lock.yml
@@ -289,9 +289,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -306,6 +303,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -406,51 +562,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -570,156 +681,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml
index d0595bcce2f..2783a678980 100644
--- a/.github/workflows/tidy.lock.yml
+++ b/.github/workflows/tidy.lock.yml
@@ -733,9 +733,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -750,6 +747,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -850,51 +1006,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1014,156 +1125,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml
index 7707803243d..2fa57ac89ce 100644
--- a/.github/workflows/typist.lock.yml
+++ b/.github/workflows/typist.lock.yml
@@ -956,9 +956,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -973,6 +970,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1073,51 +1229,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1237,156 +1348,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml
index f7cf76f9e77..514613ee10e 100644
--- a/.github/workflows/unbloat-docs.lock.yml
+++ b/.github/workflows/unbloat-docs.lock.yml
@@ -1516,9 +1516,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -1533,6 +1530,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1633,51 +1789,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1797,156 +1908,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml
index 1b80c7b0c6f..42b159c0a99 100644
--- a/.github/workflows/video-analyzer.lock.yml
+++ b/.github/workflows/video-analyzer.lock.yml
@@ -563,9 +563,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -580,6 +577,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -680,51 +836,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -844,156 +955,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml
index 1f1800601ea..0b3bf7e46dc 100644
--- a/.github/workflows/weekly-issue-summary.lock.yml
+++ b/.github/workflows/weekly-issue-summary.lock.yml
@@ -914,9 +914,6 @@ jobs:
const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
- const encoder = new TextEncoder();
- const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
- const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
function normalizeBranchName(branchName) {
if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
return branchName;
@@ -931,6 +928,165 @@ jobs:
normalized = normalized.toLowerCase();
return normalized;
}
+ function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+ }
+ function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+ return `${typeof parsed}`;
+ } catch {
+ return "text content";
+ }
+ }
+ function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+ fs.writeFileSync(filepath, content, "utf8");
+ const description = generateCompactSchema(content);
+ return {
+ filename: filename,
+ description: description,
+ };
+ }
+ function getCurrentBranch() {
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ }
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+ if (ghRefName) {
+ return ghRefName;
+ }
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+ }
+ function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+ }
+ function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+ let patchGenerated = false;
+ let errorMessage = null;
+ try {
+ if (branchName) {
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+ let baseRef;
+ try {
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ }
+ }
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ } else {
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+ if (commitCount > 0) {
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+ if (!patchContent.trim()) {
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+ }
+ const encoder = new TextEncoder();
+ const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
+ const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
debug(`Reading config from file: ${configPath}`);
@@ -1031,51 +1187,6 @@ jobs:
};
writeMessage(res);
}
- function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
- }
- function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
- return `${typeof parsed}`;
- } catch {
- return "text content";
- }
- }
- function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
- const hash = crypto.createHash("sha256").update(content).digest("hex");
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
- fs.writeFileSync(filepath, content, "utf8");
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
- const description = generateCompactSchema(content);
- return {
- filename: filename,
- description: description,
- };
- }
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
entry.type = entry.type.replace(/-/g, "_");
@@ -1195,156 +1306,6 @@ jobs:
],
};
};
- function getCurrentBranch() {
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
- }
- function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
- }
- function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
- let patchGenerated = false;
- let errorMessage = null;
- try {
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
- let baseRef;
- try {
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
- if (commitCount > 0) {
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
- if (!patchContent.trim()) {
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
- }
const createPullRequestHandler = args => {
const entry = { ...args, type: "create_pull_request" };
const baseBranch = getBaseBranch();
diff --git a/Makefile b/Makefile
index 798f8717ff4..b235af85ba6 100644
--- a/Makefile
+++ b/Makefile
@@ -102,7 +102,7 @@ fuzz:
# Test JavaScript files
.PHONY: test-js
test-js: build-js
- cd pkg/workflow/js && npm run test:js
+ cd pkg/workflow/js && npm run test:js -- --no-file-parallelism
.PHONY: build-js
build-js:
diff --git a/pkg/workflow/bundler.go b/pkg/workflow/bundler.go
index c193a0c3ede..28a18a3a45f 100644
--- a/pkg/workflow/bundler.go
+++ b/pkg/workflow/bundler.go
@@ -16,7 +16,7 @@ var bundlerLog = logger.New("workflow:bundler")
// mainContent is the main JavaScript content that may contain require() calls
// basePath is the base directory path for resolving relative imports (e.g., "js")
func BundleJavaScriptFromSources(mainContent string, sources map[string]string, basePath string) (string, error) {
- bundlerLog.Printf("Bundling JavaScript: source_count=%d, base_path=%s", len(sources), basePath)
+ bundlerLog.Printf("Bundling JavaScript: source_count=%d, base_path=%s, main_content_size=%d bytes", len(sources), basePath, len(mainContent))
// Track already processed files to avoid circular dependencies
processed := make(map[string]bool)
@@ -37,7 +37,17 @@ func BundleJavaScriptFromSources(mainContent string, sources map[string]string,
return "", err
}
- bundlerLog.Printf("Bundling completed: processed_files=%d, output_size=%d bytes", len(processed), len(bundled))
+ // Log size information about the bundled output
+ lines := strings.Split(bundled, "\n")
+ var maxLineLength int
+ for _, line := range lines {
+ if len(line) > maxLineLength {
+ maxLineLength = len(line)
+ }
+ }
+
+ bundlerLog.Printf("Bundling completed: processed_files=%d, output_size=%d bytes, output_lines=%d, max_line_length=%d chars",
+ len(processed), len(bundled), len(lines), maxLineLength)
return bundled, nil
}
@@ -111,6 +121,8 @@ func bundleFromSources(content string, currentPath string, sources map[string]st
return "", fmt.Errorf("required file not found in sources: %s", fullPath)
}
+ bundlerLog.Printf("Inlining file: %s (size: %d bytes)", fullPath, len(requiredContent))
+
// Recursively bundle the required file
requiredDir := filepath.Dir(fullPath)
bundledRequired, err := bundleFromSources(requiredContent, requiredDir, sources, processed)
@@ -120,6 +132,7 @@ func bundleFromSources(content string, currentPath string, sources map[string]st
// Remove exports from the bundled content
cleanedRequired := removeExports(bundledRequired)
+ bundlerLog.Printf("Processed %s: original_size=%d, after_export_removal=%d", fullPath, len(bundledRequired), len(cleanedRequired))
// Add a comment indicating the inlined file
result.WriteString(fmt.Sprintf("// === Inlined from %s ===\n", requirePath))
diff --git a/pkg/workflow/js.go b/pkg/workflow/js.go
index 9120909846b..c939c4266c3 100644
--- a/pkg/workflow/js.go
+++ b/pkg/workflow/js.go
@@ -69,7 +69,31 @@ var validateErrorsScript string
var missingToolScript string
//go:embed js/safe_outputs_mcp_server.cjs
-var safeOutputsMCPServerScript string
+var safeOutputsMCPServerScriptSource string
+
+var (
+ safeOutputsMCPServerScript string
+ safeOutputsMCPServerScriptOnce sync.Once
+)
+
+// getSafeOutputsMCPServerScript returns the bundled safe_outputs_mcp_server script
+// Bundling is performed on first access and cached for subsequent calls
+func getSafeOutputsMCPServerScript() string {
+ safeOutputsMCPServerScriptOnce.Do(func() {
+ jsLog.Print("Bundling safe_outputs_mcp_server script")
+ sources := GetJavaScriptSources()
+ bundled, err := BundleJavaScriptFromSources(safeOutputsMCPServerScriptSource, sources, "")
+ if err != nil {
+ jsLog.Printf("Failed to bundle safe_outputs_mcp_server script, using source as-is: %v", err)
+ // If bundling fails, use the source as-is
+ safeOutputsMCPServerScript = safeOutputsMCPServerScriptSource
+ } else {
+ jsLog.Printf("Successfully bundled safe_outputs_mcp_server script: %d bytes", len(bundled))
+ safeOutputsMCPServerScript = bundled
+ }
+ })
+ return safeOutputsMCPServerScript
+}
//go:embed js/safe_outputs_tools.json
var safeOutputsToolsJSON string
@@ -152,25 +176,53 @@ var getRepositoryUrlScript string
//go:embed js/check_permissions_utils.cjs
var checkPermissionsUtilsScript string
+//go:embed js/normalize_branch_name.cjs
+var normalizeBranchNameScript string
+
+//go:embed js/estimate_tokens.cjs
+var estimateTokensScript string
+
+//go:embed js/generate_compact_schema.cjs
+var generateCompactSchemaScript string
+
+//go:embed js/write_large_content_to_file.cjs
+var writeLargeContentToFileScript string
+
+//go:embed js/get_current_branch.cjs
+var getCurrentBranchScript string
+
+//go:embed js/get_base_branch.cjs
+var getBaseBranchScript string
+
+//go:embed js/generate_git_patch.cjs
+var generateGitPatchJSScript string
+
// GetJavaScriptSources returns a map of all embedded JavaScript sources
// The keys are the relative paths from the js directory
func GetJavaScriptSources() map[string]string {
return map[string]string{
- "sanitize_content.cjs": sanitizeContentScript,
- "sanitize_label_content.cjs": sanitizeLabelContentScript,
- "sanitize_workflow_name.cjs": sanitizeWorkflowNameScript,
- "load_agent_output.cjs": loadAgentOutputScript,
- "staged_preview.cjs": stagedPreviewScript,
- "safe_output_helpers.cjs": safeOutputHelpersScript,
- "safe_output_validator.cjs": safeOutputValidatorScript,
- "is_truthy.cjs": isTruthyScript,
- "log_parser_bootstrap.cjs": logParserBootstrapScript,
- "log_parser_shared.cjs": logParserSharedScript,
- "update_activation_comment.cjs": updateActivationCommentScript,
- "generate_footer.cjs": generateFooterScript,
- "get_tracker_id.cjs": getTrackerIDScript,
- "get_repository_url.cjs": getRepositoryUrlScript,
- "check_permissions_utils.cjs": checkPermissionsUtilsScript,
+ "sanitize_content.cjs": sanitizeContentScript,
+ "sanitize_label_content.cjs": sanitizeLabelContentScript,
+ "sanitize_workflow_name.cjs": sanitizeWorkflowNameScript,
+ "load_agent_output.cjs": loadAgentOutputScript,
+ "staged_preview.cjs": stagedPreviewScript,
+ "safe_output_helpers.cjs": safeOutputHelpersScript,
+ "safe_output_validator.cjs": safeOutputValidatorScript,
+ "is_truthy.cjs": isTruthyScript,
+ "log_parser_bootstrap.cjs": logParserBootstrapScript,
+ "log_parser_shared.cjs": logParserSharedScript,
+ "update_activation_comment.cjs": updateActivationCommentScript,
+ "generate_footer.cjs": generateFooterScript,
+ "get_tracker_id.cjs": getTrackerIDScript,
+ "get_repository_url.cjs": getRepositoryUrlScript,
+ "check_permissions_utils.cjs": checkPermissionsUtilsScript,
+ "normalize_branch_name.cjs": normalizeBranchNameScript,
+ "estimate_tokens.cjs": estimateTokensScript,
+ "generate_compact_schema.cjs": generateCompactSchemaScript,
+ "write_large_content_to_file.cjs": writeLargeContentToFileScript,
+ "get_current_branch.cjs": getCurrentBranchScript,
+ "get_base_branch.cjs": getBaseBranchScript,
+ "generate_git_patch.cjs": generateGitPatchJSScript,
}
}
@@ -617,7 +669,7 @@ func GetLogParserBootstrap() string {
// GetSafeOutputsMCPServerScript returns the JavaScript content for the GitHub Agentic Workflows Safe Outputs MCP server
func GetSafeOutputsMCPServerScript() string {
- return safeOutputsMCPServerScript
+ return getSafeOutputsMCPServerScript()
}
// GetSafeOutputsToolsJSON returns the JSON content for the safe outputs tools definitions
diff --git a/pkg/workflow/js/estimate_tokens.cjs b/pkg/workflow/js/estimate_tokens.cjs
new file mode 100644
index 00000000000..a5fc23d08be
--- /dev/null
+++ b/pkg/workflow/js/estimate_tokens.cjs
@@ -0,0 +1,16 @@
+// @ts-check
+///
+
+/**
+ * Estimates token count from text using 4 chars per token estimate
+ * @param {string} text - The text to estimate tokens for
+ * @returns {number} Approximate token count
+ */
+function estimateTokens(text) {
+ if (!text) return 0;
+ return Math.ceil(text.length / 4);
+}
+
+module.exports = {
+ estimateTokens,
+};
diff --git a/pkg/workflow/js/estimate_tokens.test.cjs b/pkg/workflow/js/estimate_tokens.test.cjs
new file mode 100644
index 00000000000..8d2d31d7471
--- /dev/null
+++ b/pkg/workflow/js/estimate_tokens.test.cjs
@@ -0,0 +1,52 @@
+import { describe, it, expect } from "vitest";
+
+describe("estimateTokens", () => {
+ it("should estimate tokens for text", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ expect(estimateTokens("hello")).toBe(2); // 5 chars / 4 = 1.25, ceil = 2
+ expect(estimateTokens("test")).toBe(1); // 4 chars / 4 = 1
+ expect(estimateTokens("testing")).toBe(2); // 7 chars / 4 = 1.75, ceil = 2
+ });
+
+ it("should handle empty strings and null", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ expect(estimateTokens("")).toBe(0);
+ expect(estimateTokens(null)).toBe(0);
+ expect(estimateTokens(undefined)).toBe(0);
+ });
+
+ it("should handle long text", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ const longText = "a".repeat(1000);
+ expect(estimateTokens(longText)).toBe(250); // 1000 / 4 = 250
+ });
+
+ it("should round up using Math.ceil", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ expect(estimateTokens("a")).toBe(1); // 1 / 4 = 0.25, ceil = 1
+ expect(estimateTokens("ab")).toBe(1); // 2 / 4 = 0.5, ceil = 1
+ expect(estimateTokens("abc")).toBe(1); // 3 / 4 = 0.75, ceil = 1
+ expect(estimateTokens("abcd")).toBe(1); // 4 / 4 = 1
+ expect(estimateTokens("abcde")).toBe(2); // 5 / 4 = 1.25, ceil = 2
+ });
+
+ it("should handle multi-byte characters", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ // Note: This uses string length, not byte length
+ expect(estimateTokens("😀")).toBe(1); // 1 char (even though it's 4 bytes)
+ expect(estimateTokens("ä½ å¥½ä¸–ç•Œ")).toBe(1); // 4 chars / 4 = 1
+ });
+
+ it("should handle whitespace and special characters", async () => {
+ const { estimateTokens } = await import("./estimate_tokens.cjs");
+
+ expect(estimateTokens(" ")).toBe(1); // 3 spaces / 4 = 0.75, ceil = 1
+ expect(estimateTokens("\n\n\n\n")).toBe(1); // 4 newlines / 4 = 1
+ expect(estimateTokens("!@#$%")).toBe(2); // 5 special chars / 4 = 1.25, ceil = 2
+ });
+});
diff --git a/pkg/workflow/js/generate_compact_schema.cjs b/pkg/workflow/js/generate_compact_schema.cjs
new file mode 100644
index 00000000000..f990c75e2c3
--- /dev/null
+++ b/pkg/workflow/js/generate_compact_schema.cjs
@@ -0,0 +1,43 @@
+// @ts-check
+///
+
+/**
+ * Generates a compact schema description from JSON content
+ * @param {string} content - The JSON content to analyze
+ * @returns {string} Compact schema description for jq/agent
+ */
+function generateCompactSchema(content) {
+ try {
+ const parsed = JSON.parse(content);
+
+ // Generate a compact schema based on the structure
+ if (Array.isArray(parsed)) {
+ if (parsed.length === 0) {
+ return "[]";
+ }
+ // For arrays, describe the first element's structure
+ const firstItem = parsed[0];
+ if (typeof firstItem === "object" && firstItem !== null) {
+ const keys = Object.keys(firstItem);
+ return `[{${keys.join(", ")}}] (${parsed.length} items)`;
+ }
+ return `[${typeof firstItem}] (${parsed.length} items)`;
+ } else if (typeof parsed === "object" && parsed !== null) {
+ // For objects, list top-level keys
+ const keys = Object.keys(parsed);
+ if (keys.length > 10) {
+ return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
+ }
+ return `{${keys.join(", ")}}`;
+ }
+
+ return `${typeof parsed}`;
+ } catch {
+ // If not valid JSON, return generic description
+ return "text content";
+ }
+}
+
+module.exports = {
+ generateCompactSchema,
+};
diff --git a/pkg/workflow/js/generate_compact_schema.test.cjs b/pkg/workflow/js/generate_compact_schema.test.cjs
new file mode 100644
index 00000000000..0fec93ef508
--- /dev/null
+++ b/pkg/workflow/js/generate_compact_schema.test.cjs
@@ -0,0 +1,86 @@
+import { describe, it, expect } from "vitest";
+
+describe("generateCompactSchema", () => {
+ it("should handle empty arrays", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("[]")).toBe("[]");
+ });
+
+ it("should describe array of objects", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ const json = JSON.stringify([
+ { id: 1, name: "test", value: 10 },
+ { id: 2, name: "test2", value: 20 },
+ ]);
+ expect(generateCompactSchema(json)).toBe("[{id, name, value}] (2 items)");
+ });
+
+ it("should describe array of primitives", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("[1, 2, 3]")).toBe("[number] (3 items)");
+ expect(generateCompactSchema('["a", "b", "c"]')).toBe("[string] (3 items)");
+ expect(generateCompactSchema("[true, false]")).toBe("[boolean] (2 items)");
+ });
+
+ it("should describe objects with few keys", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ const json = JSON.stringify({ id: 1, name: "test", value: 10 });
+ expect(generateCompactSchema(json)).toBe("{id, name, value}");
+ });
+
+ it("should describe objects with many keys", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ const obj = {};
+ for (let i = 0; i < 15; i++) {
+ obj[`key${i}`] = i;
+ }
+ const json = JSON.stringify(obj);
+ const schema = generateCompactSchema(json);
+ expect(schema).toMatch(/^\{key0, key1, .+\.\.\.\} \(15 keys\)$/);
+ });
+
+ it("should handle primitives", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("123")).toBe("number");
+ expect(generateCompactSchema('"hello"')).toBe("string");
+ expect(generateCompactSchema("true")).toBe("boolean");
+ expect(generateCompactSchema("null")).toBe("object"); // JSON.parse(null) is object
+ });
+
+ it("should handle invalid JSON", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("not valid json")).toBe("text content");
+ expect(generateCompactSchema("")).toBe("text content");
+ expect(generateCompactSchema("{invalid}")).toBe("text content");
+ });
+
+ it("should handle nested structures", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ const json = JSON.stringify({
+ users: [{ id: 1, name: "test" }],
+ meta: { total: 1 },
+ });
+ expect(generateCompactSchema(json)).toBe("{users, meta}");
+ });
+
+ it("should handle single item arrays", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("[1]")).toBe("[number] (1 items)");
+ expect(generateCompactSchema('[{"id": 1}]')).toBe("[{id}] (1 items)");
+ });
+
+ it("should handle empty objects", async () => {
+ const { generateCompactSchema } = await import("./generate_compact_schema.cjs");
+
+ expect(generateCompactSchema("{}")).toBe("{}");
+ });
+});
diff --git a/pkg/workflow/js/generate_git_patch.cjs b/pkg/workflow/js/generate_git_patch.cjs
new file mode 100644
index 00000000000..af9654f28f0
--- /dev/null
+++ b/pkg/workflow/js/generate_git_patch.cjs
@@ -0,0 +1,141 @@
+// @ts-check
+///
+
+const fs = require("fs");
+const path = require("path");
+const { execSync } = require("child_process");
+
+const { getBaseBranch } = require("./get_base_branch.cjs");
+
+/**
+ * Generates a git patch file for the current changes
+ * @param {string} branchName - The branch name to generate patch for
+ * @returns {Object} Object with patch info or error
+ */
+function generateGitPatch(branchName) {
+ const patchPath = "/tmp/gh-aw/aw.patch";
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
+ const githubSha = process.env.GITHUB_SHA;
+
+ // Ensure /tmp/gh-aw directory exists
+ const patchDir = path.dirname(patchPath);
+ if (!fs.existsSync(patchDir)) {
+ fs.mkdirSync(patchDir, { recursive: true });
+ }
+
+ let patchGenerated = false;
+ let errorMessage = null;
+
+ try {
+ // Strategy 1: If we have a branch name, check if that branch exists and get its diff
+ if (branchName) {
+ // Check if the branch exists locally
+ try {
+ execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
+
+ // Determine base ref for patch generation
+ let baseRef;
+ try {
+ // Check if origin/branchName exists
+ execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
+ baseRef = `origin/${branchName}`;
+ } catch {
+ // Use merge-base with default branch
+ execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
+ baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
+ }
+
+ // Count commits to be included
+ const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
+
+ if (commitCount > 0) {
+ // Generate patch from the determined base to the branch
+ const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch (branchError) {
+ // Branch does not exist locally
+ }
+ }
+
+ // Strategy 2: Check if commits were made to current HEAD since checkout
+ if (!patchGenerated) {
+ const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
+
+ if (!githubSha) {
+ errorMessage = "GITHUB_SHA environment variable is not set";
+ } else if (currentHead === githubSha) {
+ // No commits have been made since checkout
+ } else {
+ // Check if GITHUB_SHA is an ancestor of current HEAD
+ try {
+ execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
+
+ // Count commits between GITHUB_SHA and HEAD
+ const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
+
+ if (commitCount > 0) {
+ // Generate patch from GITHUB_SHA to HEAD
+ const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
+ cwd,
+ encoding: "utf8",
+ });
+
+ if (patchContent && patchContent.trim()) {
+ fs.writeFileSync(patchPath, patchContent, "utf8");
+ patchGenerated = true;
+ }
+ }
+ } catch {
+ // GITHUB_SHA is not an ancestor of HEAD - repository state has diverged
+ }
+ }
+ }
+ } catch (error) {
+ errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
+ }
+
+ // Check if patch was generated and has content
+ if (patchGenerated && fs.existsSync(patchPath)) {
+ const patchContent = fs.readFileSync(patchPath, "utf8");
+ const patchSize = Buffer.byteLength(patchContent, "utf8");
+ const patchLines = patchContent.split("\n").length;
+
+ if (!patchContent.trim()) {
+ // Empty patch
+ return {
+ success: false,
+ error: "No changes to commit - patch is empty",
+ patchPath: patchPath,
+ patchSize: 0,
+ patchLines: 0,
+ };
+ }
+
+ return {
+ success: true,
+ patchPath: patchPath,
+ patchSize: patchSize,
+ patchLines: patchLines,
+ };
+ }
+
+ // No patch generated
+ return {
+ success: false,
+ error: errorMessage || "No changes to commit - no commits found",
+ patchPath: patchPath,
+ };
+}
+
+module.exports = {
+ generateGitPatch,
+};
diff --git a/pkg/workflow/js/generate_git_patch.test.cjs b/pkg/workflow/js/generate_git_patch.test.cjs
new file mode 100644
index 00000000000..403838e4a80
--- /dev/null
+++ b/pkg/workflow/js/generate_git_patch.test.cjs
@@ -0,0 +1,129 @@
+import { describe, it, expect, beforeEach, afterEach } from "vitest";
+
+describe("generateGitPatch", () => {
+ let originalEnv;
+
+ beforeEach(() => {
+ // Save original environment
+ originalEnv = {
+ GITHUB_SHA: process.env.GITHUB_SHA,
+ GITHUB_WORKSPACE: process.env.GITHUB_WORKSPACE,
+ DEFAULT_BRANCH: process.env.DEFAULT_BRANCH,
+ GH_AW_BASE_BRANCH: process.env.GH_AW_BASE_BRANCH,
+ };
+ });
+
+ afterEach(() => {
+ // Restore original environment
+ Object.keys(originalEnv).forEach(key => {
+ if (originalEnv[key] !== undefined) {
+ process.env[key] = originalEnv[key];
+ } else {
+ delete process.env[key];
+ }
+ });
+ });
+
+ it("should return error when no commits can be found", async () => {
+ delete process.env.GITHUB_SHA;
+ process.env.GITHUB_WORKSPACE = "/tmp/test-repo";
+
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ const result = generateGitPatch(null);
+
+ expect(result.success).toBe(false);
+ expect(result).toHaveProperty("error");
+ });
+
+ it("should return success false when no commits found", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ // Set up environment but in a way that won't find commits
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+
+ const result = generateGitPatch("nonexistent-branch");
+
+ expect(result.success).toBe(false);
+ expect(result).toHaveProperty("error");
+ expect(result).toHaveProperty("patchPath");
+ });
+
+ it("should create patch directory if it doesn't exist", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+
+ // Even if it fails, it should try to create the directory
+ const result = generateGitPatch("test-branch");
+
+ expect(result).toHaveProperty("patchPath");
+ expect(result.patchPath).toBe("/tmp/gh-aw/aw.patch");
+ });
+
+ it("should return patch info structure", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+
+ const result = generateGitPatch("test-branch");
+
+ expect(result).toHaveProperty("success");
+ expect(result).toHaveProperty("patchPath");
+ expect(typeof result.success).toBe("boolean");
+ });
+
+ it("should handle null branch name", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+
+ const result = generateGitPatch(null);
+
+ expect(result).toHaveProperty("success");
+ expect(result).toHaveProperty("patchPath");
+ });
+
+ it("should handle empty branch name", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+
+ const result = generateGitPatch("");
+
+ expect(result).toHaveProperty("success");
+ expect(result).toHaveProperty("patchPath");
+ });
+
+ it("should use default branch from environment", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+ process.env.DEFAULT_BRANCH = "develop";
+
+ const result = generateGitPatch("feature-branch");
+
+ expect(result).toHaveProperty("success");
+ // Should attempt to use develop as default branch
+ });
+
+ it("should fall back to GH_AW_BASE_BRANCH if DEFAULT_BRANCH not set", async () => {
+ const { generateGitPatch } = await import("./generate_git_patch.cjs");
+
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-repo";
+ process.env.GITHUB_SHA = "abc123";
+ delete process.env.DEFAULT_BRANCH;
+ process.env.GH_AW_BASE_BRANCH = "master";
+
+ const result = generateGitPatch("feature-branch");
+
+ expect(result).toHaveProperty("success");
+ // Should attempt to use master as base branch
+ });
+});
diff --git a/pkg/workflow/js/get_base_branch.cjs b/pkg/workflow/js/get_base_branch.cjs
new file mode 100644
index 00000000000..ded46f56b50
--- /dev/null
+++ b/pkg/workflow/js/get_base_branch.cjs
@@ -0,0 +1,14 @@
+// @ts-check
+///
+
+/**
+ * Get the base branch name from environment variable
+ * @returns {string} The base branch name (defaults to "main")
+ */
+function getBaseBranch() {
+ return process.env.GH_AW_BASE_BRANCH || "main";
+}
+
+module.exports = {
+ getBaseBranch,
+};
diff --git a/pkg/workflow/js/get_base_branch.test.cjs b/pkg/workflow/js/get_base_branch.test.cjs
new file mode 100644
index 00000000000..329f5966eef
--- /dev/null
+++ b/pkg/workflow/js/get_base_branch.test.cjs
@@ -0,0 +1,54 @@
+import { describe, it, expect, beforeEach, afterEach } from "vitest";
+
+describe("getBaseBranch", () => {
+ let originalEnv;
+
+ beforeEach(() => {
+ // Save original environment
+ originalEnv = process.env.GH_AW_BASE_BRANCH;
+ });
+
+ afterEach(() => {
+ // Restore original environment
+ if (originalEnv !== undefined) {
+ process.env.GH_AW_BASE_BRANCH = originalEnv;
+ } else {
+ delete process.env.GH_AW_BASE_BRANCH;
+ }
+ });
+
+ it("should return main by default", async () => {
+ delete process.env.GH_AW_BASE_BRANCH;
+ const { getBaseBranch } = await import("./get_base_branch.cjs");
+
+ expect(getBaseBranch()).toBe("main");
+ });
+
+ it("should return environment variable value", async () => {
+ process.env.GH_AW_BASE_BRANCH = "develop";
+ const { getBaseBranch } = await import("./get_base_branch.cjs");
+
+ expect(getBaseBranch()).toBe("develop");
+ });
+
+ it("should handle various branch names", async () => {
+ const { getBaseBranch } = await import("./get_base_branch.cjs");
+
+ process.env.GH_AW_BASE_BRANCH = "master";
+ expect(getBaseBranch()).toBe("master");
+
+ process.env.GH_AW_BASE_BRANCH = "release/v1.0";
+ expect(getBaseBranch()).toBe("release/v1.0");
+
+ process.env.GH_AW_BASE_BRANCH = "feature/new-feature";
+ expect(getBaseBranch()).toBe("feature/new-feature");
+ });
+
+ it("should return main if environment variable is empty string", async () => {
+ process.env.GH_AW_BASE_BRANCH = "";
+ const { getBaseBranch } = await import("./get_base_branch.cjs");
+
+ // Empty string is falsy, so || operator returns "main"
+ expect(getBaseBranch()).toBe("main");
+ });
+});
diff --git a/pkg/workflow/js/get_current_branch.cjs b/pkg/workflow/js/get_current_branch.cjs
new file mode 100644
index 00000000000..b0a5e0f2a2e
--- /dev/null
+++ b/pkg/workflow/js/get_current_branch.cjs
@@ -0,0 +1,44 @@
+// @ts-check
+///
+
+const { execSync } = require("child_process");
+
+/**
+ * Get the current git branch name
+ * @returns {string} The current branch name
+ */
+function getCurrentBranch() {
+ // Priority 1: Try git command first to get the actual checked-out branch
+ // This is more reliable than environment variables which may not reflect
+ // branch changes made during the workflow execution
+ const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
+ try {
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
+ encoding: "utf8",
+ cwd: cwd,
+ }).trim();
+ return branch;
+ } catch (error) {
+ // Ignore error and try fallback
+ }
+
+ // Priority 2: Fallback to GitHub Actions environment variables
+ // GITHUB_HEAD_REF is set for pull_request events and contains the source branch name
+ // GITHUB_REF_NAME is set for all events and contains the branch/tag name
+ const ghHeadRef = process.env.GITHUB_HEAD_REF;
+ const ghRefName = process.env.GITHUB_REF_NAME;
+
+ if (ghHeadRef) {
+ return ghHeadRef;
+ }
+
+ if (ghRefName) {
+ return ghRefName;
+ }
+
+ throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
+}
+
+module.exports = {
+ getCurrentBranch,
+};
diff --git a/pkg/workflow/js/get_current_branch.test.cjs b/pkg/workflow/js/get_current_branch.test.cjs
new file mode 100644
index 00000000000..19126360e39
--- /dev/null
+++ b/pkg/workflow/js/get_current_branch.test.cjs
@@ -0,0 +1,96 @@
+import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
+
+describe("getCurrentBranch", () => {
+ let originalEnv;
+
+ beforeEach(() => {
+ // Save original environment
+ originalEnv = {
+ GITHUB_HEAD_REF: process.env.GITHUB_HEAD_REF,
+ GITHUB_REF_NAME: process.env.GITHUB_REF_NAME,
+ GITHUB_WORKSPACE: process.env.GITHUB_WORKSPACE,
+ };
+
+ // Clean environment for tests
+ delete process.env.GITHUB_HEAD_REF;
+ delete process.env.GITHUB_REF_NAME;
+ delete process.env.GITHUB_WORKSPACE;
+ });
+
+ afterEach(() => {
+ // Restore original environment
+ if (originalEnv.GITHUB_HEAD_REF !== undefined) {
+ process.env.GITHUB_HEAD_REF = originalEnv.GITHUB_HEAD_REF;
+ }
+ if (originalEnv.GITHUB_REF_NAME !== undefined) {
+ process.env.GITHUB_REF_NAME = originalEnv.GITHUB_REF_NAME;
+ }
+ if (originalEnv.GITHUB_WORKSPACE !== undefined) {
+ process.env.GITHUB_WORKSPACE = originalEnv.GITHUB_WORKSPACE;
+ }
+ });
+
+ it("should return GITHUB_HEAD_REF if set", async () => {
+ process.env.GITHUB_HEAD_REF = "feature/test-branch";
+ process.env.GITHUB_REF_NAME = "other-branch";
+
+ const { getCurrentBranch } = await import("./get_current_branch.cjs");
+
+ // If git command fails, should use GITHUB_HEAD_REF
+ try {
+ const result = getCurrentBranch();
+ // Either from git or from GITHUB_HEAD_REF
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ } catch (error) {
+ // This is acceptable if we're not in a git repo
+ expect(error.message).toContain("Failed to determine current branch");
+ }
+ });
+
+ it("should return GITHUB_REF_NAME if GITHUB_HEAD_REF not set", async () => {
+ delete process.env.GITHUB_HEAD_REF;
+ process.env.GITHUB_REF_NAME = "main";
+
+ const { getCurrentBranch } = await import("./get_current_branch.cjs");
+
+ try {
+ const result = getCurrentBranch();
+ // Either from git or from GITHUB_REF_NAME
+ expect(typeof result).toBe("string");
+ expect(result.length).toBeGreaterThan(0);
+ } catch (error) {
+ // This is acceptable if we're not in a git repo
+ expect(error.message).toContain("Failed to determine current branch");
+ }
+ });
+
+ it("should throw error when no branch can be determined", async () => {
+ delete process.env.GITHUB_HEAD_REF;
+ delete process.env.GITHUB_REF_NAME;
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-git-repo";
+
+ const { getCurrentBranch } = await import("./get_current_branch.cjs");
+
+ expect(() => getCurrentBranch()).toThrow("Failed to determine current branch");
+ });
+
+ it("should prioritize GITHUB_HEAD_REF over GITHUB_REF_NAME", async () => {
+ process.env.GITHUB_HEAD_REF = "pr-branch";
+ process.env.GITHUB_REF_NAME = "main";
+ process.env.GITHUB_WORKSPACE = "/tmp/nonexistent-git-repo";
+
+ const { getCurrentBranch } = await import("./get_current_branch.cjs");
+
+ try {
+ const result = getCurrentBranch();
+ // If git fails, should fall back to GITHUB_HEAD_REF
+ if (result === "pr-branch" || result === "main") {
+ expect(result).toBeTruthy();
+ }
+ } catch (error) {
+ // This is acceptable if we're not in a git repo
+ expect(error.message).toContain("Failed to determine current branch");
+ }
+ });
+});
diff --git a/pkg/workflow/js/normalize_branch_name.cjs b/pkg/workflow/js/normalize_branch_name.cjs
new file mode 100644
index 00000000000..ce8d4473a3e
--- /dev/null
+++ b/pkg/workflow/js/normalize_branch_name.cjs
@@ -0,0 +1,54 @@
+// @ts-check
+///
+
+/**
+ * Normalizes a branch name to be a valid git branch name.
+ *
+ * IMPORTANT: Keep this function in sync with the normalizeBranchName function in upload_assets.cjs
+ *
+ * Valid characters: alphanumeric (a-z, A-Z, 0-9), dash (-), underscore (_), forward slash (/), dot (.)
+ * Max length: 128 characters
+ *
+ * The normalization process:
+ * 1. Replaces invalid characters with a single dash
+ * 2. Collapses multiple consecutive dashes to a single dash
+ * 3. Removes leading and trailing dashes
+ * 4. Truncates to 128 characters
+ * 5. Removes trailing dashes after truncation
+ * 6. Converts to lowercase
+ *
+ * @param {string} branchName - The branch name to normalize
+ * @returns {string} The normalized branch name
+ */
+function normalizeBranchName(branchName) {
+ if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
+ return branchName;
+ }
+
+ // Replace any sequence of invalid characters with a single dash
+ // Valid characters are: a-z, A-Z, 0-9, -, _, /, .
+ let normalized = branchName.replace(/[^a-zA-Z0-9\-_/.]+/g, "-");
+
+ // Collapse multiple consecutive dashes to a single dash
+ normalized = normalized.replace(/-+/g, "-");
+
+ // Remove leading and trailing dashes
+ normalized = normalized.replace(/^-+|-+$/g, "");
+
+ // Truncate to max 128 characters
+ if (normalized.length > 128) {
+ normalized = normalized.substring(0, 128);
+ }
+
+ // Ensure it doesn't end with a dash after truncation
+ normalized = normalized.replace(/-+$/, "");
+
+ // Convert to lowercase
+ normalized = normalized.toLowerCase();
+
+ return normalized;
+}
+
+module.exports = {
+ normalizeBranchName,
+};
diff --git a/pkg/workflow/js/normalize_branch_name.test.cjs b/pkg/workflow/js/normalize_branch_name.test.cjs
new file mode 100644
index 00000000000..b45c693eed4
--- /dev/null
+++ b/pkg/workflow/js/normalize_branch_name.test.cjs
@@ -0,0 +1,82 @@
+import { describe, it, expect } from "vitest";
+
+describe("normalizeBranchName", () => {
+ it("should handle valid branch names", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("feature/add-login")).toBe("feature/add-login");
+ expect(normalizeBranchName("my-branch")).toBe("my-branch");
+ expect(normalizeBranchName("v1.0.0")).toBe("v1.0.0");
+ });
+
+ it("should replace invalid characters with dashes", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("feature@test")).toBe("feature-test");
+ expect(normalizeBranchName("branch#with#hashes")).toBe("branch-with-hashes");
+ expect(normalizeBranchName("test branch name")).toBe("test-branch-name");
+ });
+
+ it("should collapse multiple dashes", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("test---branch")).toBe("test-branch");
+ expect(normalizeBranchName("a--b--c")).toBe("a-b-c");
+ });
+
+ it("should remove leading and trailing dashes", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("-test-branch-")).toBe("test-branch");
+ expect(normalizeBranchName("---test---")).toBe("test");
+ });
+
+ it("should truncate to 128 characters", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ const longName = "a".repeat(150);
+ const result = normalizeBranchName(longName);
+ expect(result.length).toBe(128);
+ expect(result).toBe("a".repeat(128));
+ });
+
+ it("should convert to lowercase", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("Feature/Add-Login")).toBe("feature/add-login");
+ expect(normalizeBranchName("MY-BRANCH")).toBe("my-branch");
+ });
+
+ it("should handle empty and invalid inputs", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("")).toBe("");
+ expect(normalizeBranchName(" ")).toBe(" ");
+ expect(normalizeBranchName(null)).toBe(null);
+ expect(normalizeBranchName(undefined)).toBe(undefined);
+ });
+
+ it("should preserve valid special characters", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("feature/test_branch-v1.0")).toBe("feature/test_branch-v1.0");
+ expect(normalizeBranchName("my_branch-123")).toBe("my_branch-123");
+ });
+
+ it("should handle complex combinations", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ expect(normalizeBranchName("Feature@Test/Branch#123")).toBe("feature-test/branch-123");
+ expect(normalizeBranchName("__test__branch__")).toBe("__test__branch__");
+ });
+
+ it("should remove trailing dashes after truncation", async () => {
+ const { normalizeBranchName } = await import("./normalize_branch_name.cjs");
+
+ // Create a string that will end with a dash after truncation
+ const longName = "a".repeat(127) + "-b";
+ const result = normalizeBranchName(longName);
+ expect(result.length).toBeLessThanOrEqual(128);
+ expect(result).not.toMatch(/-$/);
+ });
+});
diff --git a/pkg/workflow/js/package.json b/pkg/workflow/js/package.json
index b6869c8bc3c..cad6203fa4f 100644
--- a/pkg/workflow/js/package.json
+++ b/pkg/workflow/js/package.json
@@ -17,7 +17,7 @@
},
"scripts": {
"typecheck": "tsc --noEmit",
- "test": "npm run typecheck && vitest run",
+ "test": "npm run typecheck && vitest run --no-file-parallelism",
"test:js": "vitest run",
"test:js-watch": "vitest",
"test:js-coverage": "vitest run --coverage",
diff --git a/pkg/workflow/js/safe_outputs_mcp_large_content.test.cjs b/pkg/workflow/js/safe_outputs_mcp_large_content.test.cjs
index 39807f331fd..0eab1fbebf1 100644
--- a/pkg/workflow/js/safe_outputs_mcp_large_content.test.cjs
+++ b/pkg/workflow/js/safe_outputs_mcp_large_content.test.cjs
@@ -4,7 +4,7 @@ import path from "path";
import { spawn } from "child_process";
import crypto from "crypto";
-describe("safe_outputs_mcp_server.cjs large content handling", () => {
+describe.sequential("safe_outputs_mcp_server.cjs large content handling", () => {
let originalEnv;
let tempOutputDir;
let tempConfigFile;
@@ -417,16 +417,16 @@ describe("safe_outputs_mcp_server.cjs large content handling", () => {
const serverPath = path.join(__dirname, "safe_outputs_mcp_server.cjs");
return new Promise((resolve, reject) => {
- const timeout = setTimeout(() => {
- child.kill();
- reject(new Error("Test timeout"));
- }, 10000);
-
const child = spawn("node", [serverPath], {
stdio: ["pipe", "pipe", "pipe"],
env: { ...process.env },
});
+ const timeout = setTimeout(() => {
+ child.kill();
+ reject(new Error("Test timeout"));
+ }, 10000);
+
let stderr = "";
let stdout = "";
diff --git a/pkg/workflow/js/safe_outputs_mcp_server.cjs b/pkg/workflow/js/safe_outputs_mcp_server.cjs
index 2263a94fc3e..a8a0f27291f 100644
--- a/pkg/workflow/js/safe_outputs_mcp_server.cjs
+++ b/pkg/workflow/js/safe_outputs_mcp_server.cjs
@@ -6,58 +6,18 @@ const path = require("path");
const crypto = require("crypto");
const { execSync } = require("child_process");
+const { normalizeBranchName } = require("./normalize_branch_name.cjs");
+const { estimateTokens } = require("./estimate_tokens.cjs");
+const { generateCompactSchema } = require("./generate_compact_schema.cjs");
+const { writeLargeContentToFile } = require("./write_large_content_to_file.cjs");
+const { getCurrentBranch } = require("./get_current_branch.cjs");
+const { getBaseBranch } = require("./get_base_branch.cjs");
+const { generateGitPatch } = require("./generate_git_patch.cjs");
+
const encoder = new TextEncoder();
const SERVER_INFO = { name: "safeoutputs", version: "1.0.0" };
const debug = msg => process.stderr.write(`[${SERVER_INFO.name}] ${msg}\n`);
-/**
- * Normalizes a branch name to be a valid git branch name.
- *
- * IMPORTANT: Keep this function in sync with the normalizeBranchName function in upload_assets.cjs
- *
- * Valid characters: alphanumeric (a-z, A-Z, 0-9), dash (-), underscore (_), forward slash (/), dot (.)
- * Max length: 128 characters
- *
- * The normalization process:
- * 1. Replaces invalid characters with a single dash
- * 2. Collapses multiple consecutive dashes to a single dash
- * 3. Removes leading and trailing dashes
- * 4. Truncates to 128 characters
- * 5. Removes trailing dashes after truncation
- * 6. Converts to lowercase
- *
- * @param {string} branchName - The branch name to normalize
- * @returns {string} The normalized branch name
- */
-function normalizeBranchName(branchName) {
- if (!branchName || typeof branchName !== "string" || branchName.trim() === "") {
- return branchName;
- }
-
- // Replace any sequence of invalid characters with a single dash
- // Valid characters are: a-z, A-Z, 0-9, -, _, /, .
- let normalized = branchName.replace(/[^a-zA-Z0-9\-_/.]+/g, "-");
-
- // Collapse multiple consecutive dashes to a single dash
- normalized = normalized.replace(/-+/g, "-");
-
- // Remove leading and trailing dashes
- normalized = normalized.replace(/^-+|-+$/g, "");
-
- // Truncate to max 128 characters
- if (normalized.length > 128) {
- normalized = normalized.substring(0, 128);
- }
-
- // Ensure it doesn't end with a dash after truncation
- normalized = normalized.replace(/-+$/, "");
-
- // Convert to lowercase
- normalized = normalized.toLowerCase();
-
- return normalized;
-}
-
// Read configuration from file
const configPath = process.env.GH_AW_SAFE_OUTPUTS_CONFIG_PATH || "/tmp/gh-aw/safeoutputs/config.json";
let safeOutputsConfigRaw;
@@ -179,87 +139,6 @@ function replyError(id, code, message) {
writeMessage(res);
}
-/**
- * Estimates token count from text using 4 chars per token estimate
- * @param {string} text - The text to estimate tokens for
- * @returns {number} Approximate token count
- */
-function estimateTokens(text) {
- if (!text) return 0;
- return Math.ceil(text.length / 4);
-}
-
-/**
- * Generates a compact schema description from JSON content
- * @param {string} content - The JSON content to analyze
- * @returns {string} Compact schema description for jq/agent
- */
-function generateCompactSchema(content) {
- try {
- const parsed = JSON.parse(content);
-
- // Generate a compact schema based on the structure
- if (Array.isArray(parsed)) {
- if (parsed.length === 0) {
- return "[]";
- }
- // For arrays, describe the first element's structure
- const firstItem = parsed[0];
- if (typeof firstItem === "object" && firstItem !== null) {
- const keys = Object.keys(firstItem);
- return `[{${keys.join(", ")}}] (${parsed.length} items)`;
- }
- return `[${typeof firstItem}] (${parsed.length} items)`;
- } else if (typeof parsed === "object" && parsed !== null) {
- // For objects, list top-level keys
- const keys = Object.keys(parsed);
- if (keys.length > 10) {
- return `{${keys.slice(0, 10).join(", ")}, ...} (${keys.length} keys)`;
- }
- return `{${keys.join(", ")}}`;
- }
-
- return `${typeof parsed}`;
- } catch {
- // If not valid JSON, return generic description
- return "text content";
- }
-}
-
-/**
- * Writes large content to a file and returns metadata
- * @param {string} content - The content to write
- * @returns {Object} Object with filename and description
- */
-function writeLargeContentToFile(content) {
- const logsDir = "/tmp/gh-aw/safeoutputs";
-
- // Ensure directory exists
- if (!fs.existsSync(logsDir)) {
- fs.mkdirSync(logsDir, { recursive: true });
- }
-
- // Generate SHA256 hash of content
- const hash = crypto.createHash("sha256").update(content).digest("hex");
-
- // MCP tools return JSON, so always use .json extension
- const filename = `${hash}.json`;
- const filepath = path.join(logsDir, filename);
-
- // Write content to file
- fs.writeFileSync(filepath, content, "utf8");
-
- debug(`Wrote large content (${content.length} chars) to ${filepath}`);
-
- // Generate compact schema description for jq/agent
- const description = generateCompactSchema(content);
-
- return {
- filename: filename,
- description: description,
- };
-}
-
function appendSafeOutput(entry) {
if (!outputFile) throw new Error("No output file configured");
// Normalize type to use underscores (convert any dashes to underscores)
@@ -428,217 +307,6 @@ const uploadAssetHandler = args => {
};
};
-/**
- * Get the current git branch name
- * @returns {string} The current branch name
- */
-function getCurrentBranch() {
- // Priority 1: Try git command first to get the actual checked-out branch
- // This is more reliable than environment variables which may not reflect
- // branch changes made during the workflow execution
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- try {
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
- encoding: "utf8",
- cwd: cwd,
- }).trim();
- debug(`Resolved current branch from git in ${cwd}: ${branch}`);
- return branch;
- } catch (error) {
- debug(`Failed to get branch from git: ${error instanceof Error ? error.message : String(error)}`);
- }
-
- // Priority 2: Fallback to GitHub Actions environment variables
- // GITHUB_HEAD_REF is set for pull_request events and contains the source branch name
- // GITHUB_REF_NAME is set for all events and contains the branch/tag name
- const ghHeadRef = process.env.GITHUB_HEAD_REF;
- const ghRefName = process.env.GITHUB_REF_NAME;
-
- if (ghHeadRef) {
- debug(`Resolved current branch from GITHUB_HEAD_REF: ${ghHeadRef}`);
- return ghHeadRef;
- }
-
- if (ghRefName) {
- debug(`Resolved current branch from GITHUB_REF_NAME: ${ghRefName}`);
- return ghRefName;
- }
-
- throw new Error("Failed to determine current branch: git command failed and no GitHub environment variables available");
-}
-
-/**
- * Get the base branch name from environment variable
- * @returns {string} The base branch name (defaults to "main")
- */
-function getBaseBranch() {
- return process.env.GH_AW_BASE_BRANCH || "main";
-}
-
-/**
- * Generates a git patch file for the current changes
- * @param {string} branchName - The branch name to generate patch for
- * @returns {Object} Object with patch info or error
- */
-function generateGitPatch(branchName) {
- const patchPath = "/tmp/gh-aw/aw.patch";
- const cwd = process.env.GITHUB_WORKSPACE || process.cwd();
- const defaultBranch = process.env.DEFAULT_BRANCH || getBaseBranch();
- const githubSha = process.env.GITHUB_SHA;
-
- debug(`Generating git patch for branch: ${branchName}`);
- debug(`Working directory: ${cwd}`);
- debug(`Default branch: ${defaultBranch}`);
- debug(`GITHUB_SHA: ${githubSha}`);
-
- // Ensure /tmp/gh-aw directory exists
- const patchDir = path.dirname(patchPath);
- if (!fs.existsSync(patchDir)) {
- fs.mkdirSync(patchDir, { recursive: true });
- }
-
- let patchGenerated = false;
- let errorMessage = null;
-
- try {
- // Strategy 1: If we have a branch name, check if that branch exists and get its diff
- if (branchName) {
- debug(`Strategy 1: Using named branch: ${branchName}`);
-
- // Check if the branch exists locally
- try {
- execSync(`git show-ref --verify --quiet refs/heads/${branchName}`, { cwd, encoding: "utf8" });
- debug(`Branch ${branchName} exists locally`);
-
- // Determine base ref for patch generation
- let baseRef;
- try {
- // Check if origin/branchName exists
- execSync(`git show-ref --verify --quiet refs/remotes/origin/${branchName}`, { cwd, encoding: "utf8" });
- baseRef = `origin/${branchName}`;
- debug(`Using origin/${branchName} as base for patch generation`);
- } catch {
- // Use merge-base with default branch
- debug(`origin/${branchName} does not exist, using merge-base with default branch`);
- execSync(`git fetch origin ${defaultBranch}`, { cwd, encoding: "utf8" });
- baseRef = execSync(`git merge-base origin/${defaultBranch} ${branchName}`, { cwd, encoding: "utf8" }).trim();
- debug(`Using merge-base as base: ${baseRef}`);
- }
-
- // Count commits to be included
- const commitCount = parseInt(execSync(`git rev-list --count ${baseRef}..${branchName}`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits in patch: ${commitCount}`);
-
- if (commitCount > 0) {
- // Generate patch from the determined base to the branch
- const patchContent = execSync(`git format-patch ${baseRef}..${branchName} --stdout`, {
- cwd,
- encoding: "utf8",
- });
-
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from branch: ${branchName} (base: ${baseRef})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between ${baseRef} and ${branchName}`);
- }
- } catch (branchError) {
- debug(`Branch ${branchName} does not exist locally: ${branchError instanceof Error ? branchError.message : String(branchError)}`);
- }
- }
-
- // Strategy 2: Check if commits were made to current HEAD since checkout
- if (!patchGenerated) {
- debug(`Strategy 2: Checking for commits on current HEAD`);
-
- const currentHead = execSync("git rev-parse HEAD", { cwd, encoding: "utf8" }).trim();
- debug(`Current HEAD: ${currentHead}`);
- debug(`Checkout SHA (GITHUB_SHA): ${githubSha}`);
-
- if (!githubSha) {
- errorMessage = "GITHUB_SHA environment variable is not set";
- debug(`ERROR: ${errorMessage}`);
- } else if (currentHead === githubSha) {
- debug("No commits have been made since checkout (HEAD == GITHUB_SHA)");
- } else {
- // Check if GITHUB_SHA is an ancestor of current HEAD
- try {
- execSync(`git merge-base --is-ancestor ${githubSha} HEAD`, { cwd, encoding: "utf8" });
- debug("GITHUB_SHA is an ancestor of HEAD - commits were added");
-
- // Count commits between GITHUB_SHA and HEAD
- const commitCount = parseInt(execSync(`git rev-list --count ${githubSha}..HEAD`, { cwd, encoding: "utf8" }).trim(), 10);
- debug(`Number of commits added since checkout: ${commitCount}`);
-
- if (commitCount > 0) {
- // Generate patch from GITHUB_SHA to HEAD
- const patchContent = execSync(`git format-patch ${githubSha}..HEAD --stdout`, {
- cwd,
- encoding: "utf8",
- });
-
- if (patchContent && patchContent.trim()) {
- fs.writeFileSync(patchPath, patchContent, "utf8");
- debug(`Patch file created from commits on HEAD (base: ${githubSha})`);
- patchGenerated = true;
- } else {
- debug(`No patch content generated (empty diff)`);
- }
- } else {
- debug(`No commits found between GITHUB_SHA and HEAD`);
- }
- } catch {
- debug("GITHUB_SHA is not an ancestor of HEAD - repository state has diverged");
- }
- }
- }
- } catch (error) {
- errorMessage = `Failed to generate patch: ${error instanceof Error ? error.message : String(error)}`;
- debug(`ERROR: ${errorMessage}`);
- }
-
- // Check if patch was generated and has content
- if (patchGenerated && fs.existsSync(patchPath)) {
- const patchContent = fs.readFileSync(patchPath, "utf8");
- const patchSize = Buffer.byteLength(patchContent, "utf8");
- const patchLines = patchContent.split("\n").length;
-
- if (!patchContent.trim()) {
- // Empty patch
- debug("Patch file is empty - no changes to commit");
- return {
- success: false,
- error: "No changes to commit - patch is empty",
- patchPath: patchPath,
- patchSize: 0,
- patchLines: 0,
- };
- }
-
- debug(`Patch file created: ${patchPath}`);
- debug(`Patch size: ${patchSize} bytes`);
- debug(`Patch lines: ${patchLines}`);
-
- return {
- success: true,
- patchPath: patchPath,
- patchSize: patchSize,
- patchLines: patchLines,
- };
- }
-
- // No patch generated
- return {
- success: false,
- error: errorMessage || "No changes to commit - no commits found",
- patchPath: patchPath,
- };
-}
-
/**
* Handler for create_pull_request tool
* Resolves the current branch if branch is not provided or is the base branch
diff --git a/pkg/workflow/js/safe_outputs_mcp_server_defaults.test.cjs b/pkg/workflow/js/safe_outputs_mcp_server_defaults.test.cjs
index 96478a22f20..3cb983ca8af 100644
--- a/pkg/workflow/js/safe_outputs_mcp_server_defaults.test.cjs
+++ b/pkg/workflow/js/safe_outputs_mcp_server_defaults.test.cjs
@@ -4,7 +4,7 @@ import path from "path";
import { spawn } from "child_process";
// Test defaults for safe outputs MCP server
-describe("safe_outputs_mcp_server.cjs defaults handling", () => {
+describe.sequential("safe_outputs_mcp_server.cjs defaults handling", () => {
let originalEnv;
let tempConfigFile;
let tempOutputDir;
@@ -348,7 +348,7 @@ describe("safe_outputs_mcp_server.cjs defaults handling", () => {
});
// Test that add_labels tool description is patched with allowed labels
-describe("safe_outputs_mcp_server.cjs add_labels tool patching", () => {
+describe.sequential("safe_outputs_mcp_server.cjs add_labels tool patching", () => {
it("should patch add_labels tool description with allowed labels from config", async () => {
const config = {
add_labels: {
@@ -568,7 +568,7 @@ describe("safe_outputs_mcp_server.cjs add_labels tool patching", () => {
});
// Test that update_issue tool description is patched with allowed operations
-describe("safe_outputs_mcp_server.cjs update_issue tool patching", () => {
+describe.sequential("safe_outputs_mcp_server.cjs update_issue tool patching", () => {
it("should patch update_issue tool description with allowed operations when some are restricted", async () => {
const config = {
update_issue: {
@@ -793,11 +793,6 @@ describe("safe_outputs_mcp_server.cjs update_issue tool patching", () => {
const serverPath = path.join(__dirname, "safe_outputs_mcp_server.cjs");
return new Promise((resolve, reject) => {
- const timeout = setTimeout(() => {
- child.kill();
- reject(new Error("Test timeout"));
- }, 5000);
-
const child = spawn("node", [serverPath], {
stdio: ["pipe", "pipe", "pipe"],
env: {
@@ -807,6 +802,11 @@ describe("safe_outputs_mcp_server.cjs update_issue tool patching", () => {
},
});
+ const timeout = setTimeout(() => {
+ child.kill();
+ reject(new Error("Test timeout"));
+ }, 5000);
+
let receivedMessages = [];
child.stdout.on("data", data => {
@@ -883,7 +883,7 @@ describe("safe_outputs_mcp_server.cjs update_issue tool patching", () => {
});
// Test that upload_asset tool description is patched with constraints from environment
-describe("safe_outputs_mcp_server.cjs upload_asset tool patching", () => {
+describe.sequential("safe_outputs_mcp_server.cjs upload_asset tool patching", () => {
it("should patch upload_asset tool description with max size and allowed extensions", async () => {
const config = {
upload_asset: {},
@@ -1101,7 +1101,7 @@ describe("safe_outputs_mcp_server.cjs upload_asset tool patching", () => {
});
// Test that create_pull_request and push_to_pull_request_branch tools have optional branch parameter
-describe("safe_outputs_mcp_server.cjs branch parameter handling", () => {
+describe.sequential("safe_outputs_mcp_server.cjs branch parameter handling", () => {
it("should have optional branch parameter for create_pull_request", async () => {
const config = {
create_pull_request: {},
@@ -1314,7 +1314,7 @@ describe("safe_outputs_mcp_server.cjs branch parameter handling", () => {
});
// Test that tool call responses include the isError field
-describe("safe_outputs_mcp_server.cjs tool call response format", () => {
+describe.sequential("safe_outputs_mcp_server.cjs tool call response format", () => {
it("should include isError field in tool call responses", async () => {
const config = {
create_issue: {},
diff --git a/pkg/workflow/js/write_large_content_to_file.cjs b/pkg/workflow/js/write_large_content_to_file.cjs
new file mode 100644
index 00000000000..89561cf2763
--- /dev/null
+++ b/pkg/workflow/js/write_large_content_to_file.cjs
@@ -0,0 +1,44 @@
+// @ts-check
+///
+
+const fs = require("fs");
+const path = require("path");
+const crypto = require("crypto");
+
+const { generateCompactSchema } = require("./generate_compact_schema.cjs");
+
+/**
+ * Writes large content to a file and returns metadata
+ * @param {string} content - The content to write
+ * @returns {Object} Object with filename and description
+ */
+function writeLargeContentToFile(content) {
+ const logsDir = "/tmp/gh-aw/safeoutputs";
+
+ // Ensure directory exists
+ if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir, { recursive: true });
+ }
+
+ // Generate SHA256 hash of content
+ const hash = crypto.createHash("sha256").update(content).digest("hex");
+
+ // MCP tools return JSON, so always use .json extension
+ const filename = `${hash}.json`;
+ const filepath = path.join(logsDir, filename);
+
+ // Write content to file
+ fs.writeFileSync(filepath, content, "utf8");
+
+ // Generate compact schema description for jq/agent
+ const description = generateCompactSchema(content);
+
+ return {
+ filename: filename,
+ description: description,
+ };
+}
+
+module.exports = {
+ writeLargeContentToFile,
+};
diff --git a/pkg/workflow/js/write_large_content_to_file.test.cjs b/pkg/workflow/js/write_large_content_to_file.test.cjs
new file mode 100644
index 00000000000..02ed10601a7
--- /dev/null
+++ b/pkg/workflow/js/write_large_content_to_file.test.cjs
@@ -0,0 +1,117 @@
+import { describe, it, expect, beforeEach, afterEach } from "vitest";
+import fs from "fs";
+import path from "path";
+
+describe("writeLargeContentToFile", () => {
+ const testDir = "/tmp/gh-aw/safeoutputs";
+
+ beforeEach(() => {
+ // Clean up test directory before each test
+ if (fs.existsSync(testDir)) {
+ fs.rmSync(testDir, { recursive: true });
+ }
+ });
+
+ afterEach(() => {
+ // Clean up test directory after each test
+ if (fs.existsSync(testDir)) {
+ fs.rmSync(testDir, { recursive: true });
+ }
+ });
+
+ it("should create directory if it doesn't exist", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ expect(fs.existsSync(testDir)).toBe(false);
+
+ const content = JSON.stringify({ test: "data" });
+ writeLargeContentToFile(content);
+
+ expect(fs.existsSync(testDir)).toBe(true);
+ });
+
+ it("should write content to file with hash-based filename", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content = JSON.stringify({ test: "data" });
+ const result = writeLargeContentToFile(content);
+
+ expect(result).toHaveProperty("filename");
+ expect(result.filename).toMatch(/^[a-f0-9]{64}\.json$/);
+
+ const filepath = path.join(testDir, result.filename);
+ expect(fs.existsSync(filepath)).toBe(true);
+
+ const written = fs.readFileSync(filepath, "utf8");
+ expect(written).toBe(content);
+ });
+
+ it("should return schema description", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content = JSON.stringify({ id: 1, name: "test", value: 10 });
+ const result = writeLargeContentToFile(content);
+
+ expect(result).toHaveProperty("description");
+ expect(result.description).toBe("{id, name, value}");
+ });
+
+ it("should use .json extension", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content = JSON.stringify([1, 2, 3]);
+ const result = writeLargeContentToFile(content);
+
+ expect(result.filename).toMatch(/\.json$/);
+ });
+
+ it("should generate consistent hash for same content", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content = JSON.stringify({ test: "data" });
+ const result1 = writeLargeContentToFile(content);
+ const result2 = writeLargeContentToFile(content);
+
+ expect(result1.filename).toBe(result2.filename);
+ });
+
+ it("should generate different hash for different content", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content1 = JSON.stringify({ test: "data1" });
+ const content2 = JSON.stringify({ test: "data2" });
+
+ const result1 = writeLargeContentToFile(content1);
+ const result2 = writeLargeContentToFile(content2);
+
+ expect(result1.filename).not.toBe(result2.filename);
+ });
+
+ it("should handle arrays", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const content = JSON.stringify([{ id: 1 }, { id: 2 }]);
+ const result = writeLargeContentToFile(content);
+
+ expect(result.description).toBe("[{id}] (2 items)");
+ });
+
+ it("should handle large content", async () => {
+ const { writeLargeContentToFile } = await import("./write_large_content_to_file.cjs");
+
+ const largeObj = {};
+ for (let i = 0; i < 1000; i++) {
+ largeObj[`key${i}`] = `value${i}`;
+ }
+ const content = JSON.stringify(largeObj);
+
+ const result = writeLargeContentToFile(content);
+
+ expect(result).toHaveProperty("filename");
+ expect(result).toHaveProperty("description");
+
+ const filepath = path.join(testDir, result.filename);
+ const written = fs.readFileSync(filepath, "utf8");
+ expect(written).toBe(content);
+ });
+});
diff --git a/pkg/workflow/mcp_servers.go b/pkg/workflow/mcp_servers.go
index 4100826a457..4f64afeef95 100644
--- a/pkg/workflow/mcp_servers.go
+++ b/pkg/workflow/mcp_servers.go
@@ -141,7 +141,7 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any,
yaml.WriteString(" cat > /tmp/gh-aw/safeoutputs/mcp-server.cjs << 'EOF'\n")
// Embed the safe-outputs MCP server script
- for _, line := range FormatJavaScriptForYAML(safeOutputsMCPServerScript) {
+ for _, line := range FormatJavaScriptForYAML(GetSafeOutputsMCPServerScript()) {
yaml.WriteString(line)
}
yaml.WriteString(" EOF\n")