From 6616dd8acf655dd08c07158df4a09ae8efdfb8d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:15:14 +0000 Subject: [PATCH 1/5] Initial plan From 8bf917cdddc50626d2bf475ada1b85ebed37da78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:40:09 +0000 Subject: [PATCH 2/5] Add 10KB patch size limit for repo-memory safe output updates - Add MaxPatchSize field to RepoMemoryEntry with 10KB default - Parse max-patch-size config option with bounds validation - Pass MAX_PATCH_SIZE env var to push step - Validate patch size after staging via git diff --cached - Add tests for default, bounds validation, and array notation - Update scratchpad/repo-memory.md spec with new validation rule - Update docs with max-patch-size option and troubleshooting Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../agent-performance-analyzer.lock.yml | 1 + .github/workflows/audit-workflows.lock.yml | 1 + .../workflows/code-scanning-fixer.lock.yml | 1 + .../workflows/copilot-agent-analysis.lock.yml | 1 + .../copilot-cli-deep-research.lock.yml | 1 + .../copilot-pr-nlp-analysis.lock.yml | 1 + .../copilot-pr-prompt-analysis.lock.yml | 1 + .../copilot-session-insights.lock.yml | 1 + .../workflows/daily-cli-performance.lock.yml | 1 + .github/workflows/daily-code-metrics.lock.yml | 1 + .../daily-copilot-token-report.lock.yml | 1 + .github/workflows/daily-news.lock.yml | 1 + .../daily-testify-uber-super-expert.lock.yml | 1 + .github/workflows/deep-report.lock.yml | 1 + .github/workflows/delight.lock.yml | 1 + .../workflows/discussion-task-miner.lock.yml | 1 + .github/workflows/firewall-escape.lock.yml | 1 + .github/workflows/metrics-collector.lock.yml | 1 + .github/workflows/pr-triage-agent.lock.yml | 1 + .../workflows/security-compliance.lock.yml | 1 + .../workflow-health-manager.lock.yml | 1 + actions/setup/js/push_repo_memory.cjs | 19 +++ .../src/content/docs/reference/repo-memory.md | 8 +- pkg/workflow/repo_memory.go | 36 ++++ pkg/workflow/repo_memory_test.go | 154 ++++++++++++++++++ scratchpad/repo-memory.md | 34 +++- 26 files changed, 269 insertions(+), 3 deletions(-) diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index a4207ba38f2..34e0104548c 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -1337,6 +1337,7 @@ jobs: BRANCH_NAME: memory/meta-orchestrators MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "**" with: diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index d0bebc93545..6b015c4440b 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -1356,6 +1356,7 @@ jobs: BRANCH_NAME: memory/audit-workflows MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/audit-workflows/*.json memory/audit-workflows/*.jsonl memory/audit-workflows/*.csv memory/audit-workflows/*.md" with: diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index 2f33592abb8..ae75e256a39 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -1252,6 +1252,7 @@ jobs: BRANCH_NAME: memory/campaigns MAX_FILE_SIZE: 10240 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "security-alert-burndown/**" with: diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 76079e2c2e2..b9cdc245cba 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -1228,6 +1228,7 @@ jobs: BRANCH_NAME: memory/copilot-agent-analysis MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/copilot-agent-analysis/*.json memory/copilot-agent-analysis/*.jsonl memory/copilot-agent-analysis/*.csv memory/copilot-agent-analysis/*.md" with: diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml index e6b43ffe225..50f2ed1426d 100644 --- a/.github/workflows/copilot-cli-deep-research.lock.yml +++ b/.github/workflows/copilot-cli-deep-research.lock.yml @@ -1147,6 +1147,7 @@ jobs: BRANCH_NAME: memory/copilot-cli-research MAX_FILE_SIZE: 204800 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/copilot-cli-research/*.json memory/copilot-cli-research/*.md" with: diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index afddfa00ae8..e41d41b0f95 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -1243,6 +1243,7 @@ jobs: BRANCH_NAME: memory/nlp-analysis MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/nlp-analysis/*.json memory/nlp-analysis/*.jsonl memory/nlp-analysis/*.csv memory/nlp-analysis/*.md" with: diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 9381fc5c072..15f0eac6062 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -1167,6 +1167,7 @@ jobs: BRANCH_NAME: memory/prompt-analysis MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/prompt-analysis/*.json memory/prompt-analysis/*.jsonl memory/prompt-analysis/*.csv memory/prompt-analysis/*.md" with: diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 8e09b2fa972..11931a23cb9 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -1307,6 +1307,7 @@ jobs: BRANCH_NAME: memory/session-insights MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/session-insights/*.json memory/session-insights/*.jsonl memory/session-insights/*.csv memory/session-insights/*.md" with: diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml index 310d6905d6a..46f3a3624a5 100644 --- a/.github/workflows/daily-cli-performance.lock.yml +++ b/.github/workflows/daily-cli-performance.lock.yml @@ -1337,6 +1337,7 @@ jobs: BRANCH_NAME: memory/cli-performance MAX_FILE_SIZE: 512000 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/cli-performance/*.json memory/cli-performance/*.jsonl memory/cli-performance/*.txt" with: diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index ca2bc3a1942..cf558f77151 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -1285,6 +1285,7 @@ jobs: BRANCH_NAME: daily/daily-code-metrics MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "*.json *.jsonl *.csv *.md" with: diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index 400a7850838..de9c6a2715d 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -1254,6 +1254,7 @@ jobs: BRANCH_NAME: memory/token-metrics MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/token-metrics/*.json memory/token-metrics/*.jsonl memory/token-metrics/*.csv memory/token-metrics/*.md" with: diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index f1a9944fe81..aa73210c66e 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -1316,6 +1316,7 @@ jobs: BRANCH_NAME: memory/daily-news MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/daily-news/*.json memory/daily-news/*.jsonl memory/daily-news/*.csv memory/daily-news/*.md" with: diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index ee8b3f11403..409355ee80b 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -1230,6 +1230,7 @@ jobs: BRANCH_NAME: memory/testify-expert MAX_FILE_SIZE: 51200 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/testify-expert/*.json memory/testify-expert/*.txt" with: diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index b78cfdf544b..945b4cc1821 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -1353,6 +1353,7 @@ jobs: BRANCH_NAME: memory/deep-report MAX_FILE_SIZE: 1048576 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/deep-report/*.md" with: diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml index 68e6bb314a5..3de45083e2b 100644 --- a/.github/workflows/delight.lock.yml +++ b/.github/workflows/delight.lock.yml @@ -1232,6 +1232,7 @@ jobs: BRANCH_NAME: memory/delight MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/delight/*.json memory/delight/*.md" with: diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml index 40b48072090..cac3afcff7b 100644 --- a/.github/workflows/discussion-task-miner.lock.yml +++ b/.github/workflows/discussion-task-miner.lock.yml @@ -1213,6 +1213,7 @@ jobs: BRANCH_NAME: memory/discussion-task-miner MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/discussion-task-miner/*.json memory/discussion-task-miner/*.md" with: diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml index e244797f481..7816ed5bc14 100644 --- a/.github/workflows/firewall-escape.lock.yml +++ b/.github/workflows/firewall-escape.lock.yml @@ -1228,6 +1228,7 @@ jobs: BRANCH_NAME: memory/firewall-escape MAX_FILE_SIZE: 524288 MAX_FILE_COUNT: 50 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' with: script: | diff --git a/.github/workflows/metrics-collector.lock.yml b/.github/workflows/metrics-collector.lock.yml index 87d92d2a02b..17f2c4dda93 100644 --- a/.github/workflows/metrics-collector.lock.yml +++ b/.github/workflows/metrics-collector.lock.yml @@ -709,6 +709,7 @@ jobs: BRANCH_NAME: memory/meta-orchestrators MAX_FILE_SIZE: 10240 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "metrics/**" with: diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index d573c59c83b..cbc4ed01fd3 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -1215,6 +1215,7 @@ jobs: BRANCH_NAME: memory/pr-triage MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "**" with: diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml index c6da9f6ccfc..cd865b6f59f 100644 --- a/.github/workflows/security-compliance.lock.yml +++ b/.github/workflows/security-compliance.lock.yml @@ -1163,6 +1163,7 @@ jobs: BRANCH_NAME: memory/campaigns MAX_FILE_SIZE: 10240 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "memory/campaigns/security-compliance-*/**" with: diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml index 5131005fe54..d8997816ff5 100644 --- a/.github/workflows/workflow-health-manager.lock.yml +++ b/.github/workflows/workflow-health-manager.lock.yml @@ -1333,6 +1333,7 @@ jobs: BRANCH_NAME: memory/meta-orchestrators MAX_FILE_SIZE: 102400 MAX_FILE_COUNT: 100 + MAX_PATCH_SIZE: 10240 ALLOWED_EXTENSIONS: '[]' FILE_GLOB_FILTER: "**" with: diff --git a/actions/setup/js/push_repo_memory.cjs b/actions/setup/js/push_repo_memory.cjs index 9517bb813de..768e013f537 100644 --- a/actions/setup/js/push_repo_memory.cjs +++ b/actions/setup/js/push_repo_memory.cjs @@ -18,6 +18,7 @@ const { parseAllowedRepos, validateRepo } = require("./repo_helpers.cjs"); * BRANCH_NAME: Branch name to push to * MAX_FILE_SIZE: Maximum file size in bytes * MAX_FILE_COUNT: Maximum number of files per commit + * MAX_PATCH_SIZE: Maximum total patch size in bytes (default: 10240 = 10KB) * ALLOWED_EXTENSIONS: JSON array of allowed file extensions (e.g., '[".json",".txt"]') * FILE_GLOB_FILTER: Optional space-separated list of file patterns (e.g., "*.md metrics/** data/**") * Supports * (matches any chars except /) and ** (matches any chars including /) @@ -44,6 +45,7 @@ async function main() { const branchName = process.env.BRANCH_NAME; const maxFileSize = parseInt(process.env.MAX_FILE_SIZE || "10240", 10); const maxFileCount = parseInt(process.env.MAX_FILE_COUNT || "100", 10); + const maxPatchSize = parseInt(process.env.MAX_PATCH_SIZE || "10240", 10); const fileGlobFilter = process.env.FILE_GLOB_FILTER || ""; // Parse allowed extensions with error handling @@ -67,6 +69,7 @@ async function main() { core.info(` MEMORY_ID: ${memoryId}`); core.info(` MAX_FILE_SIZE: ${maxFileSize}`); core.info(` MAX_FILE_COUNT: ${maxFileCount}`); + core.info(` MAX_PATCH_SIZE: ${maxPatchSize}`); core.info(` ALLOWED_EXTENSIONS: ${JSON.stringify(allowedExtensions)}`); core.info(` FILE_GLOB_FILTER: ${fileGlobFilter ? `"${fileGlobFilter}"` : "(empty - all files accepted)"}`); core.info(` FILE_GLOB_FILTER length: ${fileGlobFilter.length}`); @@ -337,6 +340,22 @@ async function main() { return; } + // Validate total patch size before committing + try { + const patchContent = execGitSync(["diff", "--cached"], { stdio: "pipe" }); + const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); + const patchSizeKb = Math.ceil(patchSizeBytes / 1024); + const maxPatchSizeKb = Math.ceil(maxPatchSize / 1024); + core.info(`Patch size: ${patchSizeKb} KB (maximum allowed: ${maxPatchSizeKb} KB)`); + if (patchSizeBytes > maxPatchSize) { + core.setFailed(`Patch size (${patchSizeKb} KB) exceeds maximum allowed size (${maxPatchSizeKb} KB). Reduce the number or size of changes, or increase max-patch-size.`); + return; + } + } catch (error) { + core.setFailed(`Failed to compute patch size: ${getErrorMessage(error)}`); + return; + } + // Commit changes try { execGitSync(["commit", "-m", `Update repo memory from workflow run ${githubRunId}`], { stdio: "inherit" }); diff --git a/docs/src/content/docs/reference/repo-memory.md b/docs/src/content/docs/reference/repo-memory.md index 0cba7ee7d39..d4a2c21c974 100644 --- a/docs/src/content/docs/reference/repo-memory.md +++ b/docs/src/content/docs/reference/repo-memory.md @@ -30,6 +30,7 @@ tools: file-glob: ["memory/custom-agent-for-aw/*.md", "memory/custom-agent-for-aw/*.json"] max-file-size: 1048576 # 1MB (default 10KB) max-file-count: 50 # default 100 + max-patch-size: 51200 # 50KB (default 10KB) target-repo: "owner/repository" create-orphan: true # default allowed-extensions: [".json", ".txt", ".md"] # Restrict file types (default: empty/all files allowed) @@ -40,6 +41,8 @@ tools: **File Type Restrictions**: Use `allowed-extensions` to restrict which file types can be stored (default: empty/all files allowed). When specified, only files with listed extensions (e.g., `[".json", ".txt", ".md"]`) can be saved. Files with disallowed extensions will trigger validation failures. +**Patch Size Limit**: Use `max-patch-size` to limit the total size of changes in a single push (default: 10KB). The total size of the git diff (all staged changes combined) must not exceed this value. If it does, the push is rejected with an error. Use this to prevent large unintentional memory updates. + **Note**: File glob patterns must include the full branch path structure. For branch `memory/custom-agent-for-aw`, use patterns like `memory/custom-agent-for-aw/*.json` to match files stored at that path within the branch. ## Multiple Configurations @@ -80,7 +83,8 @@ For fast 7-day caching without version control, see [Cache Memory](/gh-aw/refere - **Branch not created**: Ensure `create-orphan: true` or create manually. - **Permission denied**: Compiler auto-adds `contents: write`. -- **Validation failures**: Match `file-glob`, stay under `max-file-size` (10KB default) and `max-file-count` (100 default). +- **Validation failures**: Match `file-glob`, stay under `max-file-size` (10KB default), `max-file-count` (100 default), and `max-patch-size` (10KB default). +- **Patch too large**: If the total diff exceeds `max-patch-size` (default 10KB), the push is rejected. Reduce the number or size of changes, or increase `max-patch-size` in the configuration. - **Changes not persisting**: Check directory path, workflow completion, push errors in logs. - **Merge conflicts**: Uses `-X ours` (your changes win). Read before writing to preserve data. @@ -88,7 +92,7 @@ For fast 7-day caching without version control, see [Cache Memory](/gh-aw/refere Don't store sensitive data in repo memory. Repo memory follows repository permissions. -Use private repos for sensitive data, avoid storing secrets, set constraints (`file-glob`, `max-file-size`, `max-file-count`), consider branch protection, use `target-repo` to isolate. +Use private repos for sensitive data, avoid storing secrets, set constraints (`file-glob`, `max-file-size`, `max-file-count`, `max-patch-size`), consider branch protection, use `target-repo` to isolate. ## Examples diff --git a/pkg/workflow/repo_memory.go b/pkg/workflow/repo_memory.go index 62971cf03aa..991f794696c 100644 --- a/pkg/workflow/repo_memory.go +++ b/pkg/workflow/repo_memory.go @@ -50,6 +50,7 @@ type RepoMemoryEntry struct { FileGlob []string `yaml:"file-glob,omitempty"` // file glob patterns for allowed files MaxFileSize int `yaml:"max-file-size,omitempty"` // maximum size per file in bytes (default: 10KB) MaxFileCount int `yaml:"max-file-count,omitempty"` // maximum file count per commit (default: 100) + MaxPatchSize int `yaml:"max-patch-size,omitempty"` // maximum total patch size in bytes (default: 10KB) Description string `yaml:"description,omitempty"` // optional description for this memory CreateOrphan bool `yaml:"create-orphan,omitempty"` // create orphaned branch if missing (default: true) AllowedExtensions []string `yaml:"allowed-extensions,omitempty"` // allowed file extensions (default: [".json", ".jsonl", ".txt", ".md", ".csv"]) @@ -130,6 +131,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), MaxFileSize: 10240, // 10KB MaxFileCount: 100, + MaxPatchSize: 10240, // 10KB CreateOrphan: true, AllowedExtensions: constants.DefaultAllowedMemoryExtensions, }, @@ -148,6 +150,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), MaxFileSize: 10240, // 10KB MaxFileCount: 100, + MaxPatchSize: 10240, // 10KB CreateOrphan: true, AllowedExtensions: constants.DefaultAllowedMemoryExtensions, }, @@ -185,6 +188,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry := RepoMemoryEntry{ MaxFileSize: 10240, // 10KB default MaxFileCount: 100, // 100 files default + MaxPatchSize: 10240, // 10KB default CreateOrphan: true, // create orphan by default } @@ -269,6 +273,21 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID } } + // Parse max-patch-size + if maxPatchSize, exists := memoryMap["max-patch-size"]; exists { + if sizeInt, ok := maxPatchSize.(int); ok { + entry.MaxPatchSize = sizeInt + } else if sizeFloat, ok := maxPatchSize.(float64); ok { + entry.MaxPatchSize = int(sizeFloat) + } else if sizeUint64, ok := maxPatchSize.(uint64); ok { + entry.MaxPatchSize = int(sizeUint64) + } + // Validate max-patch-size bounds + if err := validateIntRange(entry.MaxPatchSize, 1, 104857600, "max-patch-size"); err != nil { + return nil, err + } + } + // Parse description if description, exists := memoryMap["description"]; exists { if descStr, ok := description.(string); ok { @@ -332,6 +351,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), MaxFileSize: 10240, // 10KB default MaxFileCount: 100, // 100 files default + MaxPatchSize: 10240, // 10KB default CreateOrphan: true, // create orphan by default } @@ -394,6 +414,21 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID } } + // Parse max-patch-size + if maxPatchSize, exists := configMap["max-patch-size"]; exists { + if sizeInt, ok := maxPatchSize.(int); ok { + entry.MaxPatchSize = sizeInt + } else if sizeFloat, ok := maxPatchSize.(float64); ok { + entry.MaxPatchSize = int(sizeFloat) + } else if sizeUint64, ok := maxPatchSize.(uint64); ok { + entry.MaxPatchSize = int(sizeUint64) + } + // Validate max-patch-size bounds + if err := validateIntRange(entry.MaxPatchSize, 1, 104857600, "max-patch-size"); err != nil { + return nil, err + } + } + // Parse description if description, exists := configMap["description"]; exists { if descStr, ok := description.(string); ok { @@ -680,6 +715,7 @@ func (c *Compiler) buildPushRepoMemoryJob(data *WorkflowData, threatDetectionEna fmt.Fprintf(&step, " BRANCH_NAME: %s\n", memory.BranchName) fmt.Fprintf(&step, " MAX_FILE_SIZE: %d\n", memory.MaxFileSize) fmt.Fprintf(&step, " MAX_FILE_COUNT: %d\n", memory.MaxFileCount) + fmt.Fprintf(&step, " MAX_PATCH_SIZE: %d\n", memory.MaxPatchSize) // Pass allowed extensions as JSON array allowedExtsJSON, _ := json.Marshal(memory.AllowedExtensions) fmt.Fprintf(&step, " ALLOWED_EXTENSIONS: '%s'\n", allowedExtsJSON) diff --git a/pkg/workflow/repo_memory_test.go b/pkg/workflow/repo_memory_test.go index 9b249c43fec..2ae7ab40065 100644 --- a/pkg/workflow/repo_memory_test.go +++ b/pkg/workflow/repo_memory_test.go @@ -650,6 +650,160 @@ func TestRepoMemoryMaxFileCountValidationArray(t *testing.T) { } } +// TestRepoMemoryMaxPatchSizeDefault tests that max-patch-size defaults to 10KB +func TestRepoMemoryMaxPatchSizeDefault(t *testing.T) { + toolsMap := map[string]any{ + "repo-memory": true, + } + + toolsConfig, err := ParseToolsConfig(toolsMap) + require.NoError(t, err, "Should parse tools config") + + compiler := NewCompiler() + config, err := compiler.extractRepoMemoryConfig(toolsConfig, "my-workflow") + require.NoError(t, err, "Should extract repo-memory config") + require.NotNil(t, config, "Config should not be nil") + require.Len(t, config.Memories, 1, "Should have 1 memory") + + assert.Equal(t, 10240, config.Memories[0].MaxPatchSize, "Default max patch size should be 10240 bytes (10KB)") +} + +// TestRepoMemoryMaxPatchSizeValidation tests max-patch-size boundary validation +func TestRepoMemoryMaxPatchSizeValidation(t *testing.T) { + tests := []struct { + name string + maxPatchSize int + wantError bool + errorText string + }{ + { + name: "valid minimum size (1 byte)", + maxPatchSize: 1, + wantError: false, + }, + { + name: "valid maximum size (104857600 bytes)", + maxPatchSize: 104857600, + wantError: false, + }, + { + name: "valid default size (10240 bytes)", + maxPatchSize: 10240, + wantError: false, + }, + { + name: "valid custom size (51200 bytes = 50KB)", + maxPatchSize: 51200, + wantError: false, + }, + { + name: "invalid zero size", + maxPatchSize: 0, + wantError: true, + errorText: "max-patch-size must be between 1 and 104857600, got 0", + }, + { + name: "invalid negative size", + maxPatchSize: -1, + wantError: true, + errorText: "max-patch-size must be between 1 and 104857600, got -1", + }, + { + name: "invalid size exceeds maximum", + maxPatchSize: 104857601, + wantError: true, + errorText: "max-patch-size must be between 1 and 104857600, got 104857601", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + toolsMap := map[string]any{ + "repo-memory": map[string]any{ + "max-patch-size": tt.maxPatchSize, + }, + } + + toolsConfig, err := ParseToolsConfig(toolsMap) + require.NoError(t, err, "Should parse tools config") + + compiler := NewCompiler() + config, err := compiler.extractRepoMemoryConfig(toolsConfig, "") + + if tt.wantError { + require.Error(t, err, "Should return an error") + if err != nil { + assert.Contains(t, err.Error(), tt.errorText, "Error message should match") + } + } else { + require.NoError(t, err, "Should not return an error") + if config != nil && len(config.Memories) > 0 { + assert.Equal(t, tt.maxPatchSize, config.Memories[0].MaxPatchSize, "MaxPatchSize should match") + } + } + }) + } +} + +// TestRepoMemoryMaxPatchSizeValidationArray tests max-patch-size validation in array notation +func TestRepoMemoryMaxPatchSizeValidationArray(t *testing.T) { + tests := []struct { + name string + maxPatchSize int + wantError bool + errorText string + }{ + { + name: "valid size in array", + maxPatchSize: 10240, + wantError: false, + }, + { + name: "invalid size in array (zero)", + maxPatchSize: 0, + wantError: true, + errorText: "max-patch-size must be between 1 and 104857600, got 0", + }, + { + name: "invalid size in array (exceeds max)", + maxPatchSize: 104857601, + wantError: true, + errorText: "max-patch-size must be between 1 and 104857600, got 104857601", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + toolsMap := map[string]any{ + "repo-memory": []any{ + map[string]any{ + "id": "test", + "max-patch-size": tt.maxPatchSize, + }, + }, + } + + toolsConfig, err := ParseToolsConfig(toolsMap) + require.NoError(t, err, "Should parse tools config") + + compiler := NewCompiler() + config, err := compiler.extractRepoMemoryConfig(toolsConfig, "") + + if tt.wantError { + require.Error(t, err, "Should return an error") + if err != nil { + assert.Contains(t, err.Error(), tt.errorText, "Error message should match") + } + } else { + require.NoError(t, err, "Should not return an error") + if config != nil && len(config.Memories) > 0 { + assert.Equal(t, tt.maxPatchSize, config.Memories[0].MaxPatchSize, "MaxPatchSize should match") + } + } + }) + } +} + // TestBranchPrefixValidation tests the validateBranchPrefix function func TestBranchPrefixValidation(t *testing.T) { tests := []struct { diff --git a/scratchpad/repo-memory.md b/scratchpad/repo-memory.md index 28d34220d0c..832a7fe7657 100644 --- a/scratchpad/repo-memory.md +++ b/scratchpad/repo-memory.md @@ -192,6 +192,7 @@ git checkout --orphan "$BRANCH_NAME" - `BRANCH_NAME` - Branch name (e.g., `memory/default`) - `MAX_FILE_SIZE` - Maximum bytes per file (default: `10240`) - `MAX_FILE_COUNT` - Maximum files per commit (default: `100`) +- `MAX_PATCH_SIZE` - Maximum total patch size in bytes (default: `10240`) - `FILE_GLOB_FILTER` - Space-separated glob patterns (e.g., `*.md metrics/**`) - `GH_AW_CAMPAIGN_ID` - Campaign ID for campaign mode validation - `GH_TOKEN` - GitHub authentication token @@ -214,6 +215,7 @@ const relativeFilePath = "history.jsonl" // NOT "memory/default/history.jsonl" - File glob patterns match against relative paths from artifact root - Branch name used for git operations, NOT for pattern matching - Campaign mode enforces schema validation for cursor and metrics files +- Patch size validation computes `git diff --cached` after staging and refuses if total exceeds `MAX_PATCH_SIZE` ## Configuration Options @@ -232,6 +234,7 @@ tools: # file-glob: string[] (default: all files) # max-file-size: int (default: 10240, max: 104857600) # max-file-count: int (default: 100, max: 1000) + # max-patch-size: int (default: 10240, max: 104857600) # description: string (optional) # create-orphan: boolean (default: true) # campaign-id: string (optional) @@ -245,6 +248,7 @@ tools: # file-glob: string[] (default: all files) # max-file-size: int (default: 10240, max: 104857600) # max-file-count: int (default: 100, max: 1000) + # max-patch-size: int (default: 10240, max: 104857600) # description: string (optional) # create-orphan: boolean (default: true) # campaign-id: string (optional) @@ -374,7 +378,35 @@ file-glob: - "memory/code-metrics/*.jsonl" # WRONG: includes branch name ``` -### 5. Campaign Mode Validation +### 5. Patch Size Limits + +The total size of all changes (git diff) in a single repo-memory push MUST not exceed the configured maximum patch size. + +- **Minimum**: 1 byte +- **Maximum**: 104857600 bytes (100 MB) +- **Default**: 10240 bytes (10 KB) +- **Configuration**: `max-patch-size` (in bytes) +- Validated during config parsing (Go layer) +- Enforced after staging changes, before committing (JavaScript layer) + +**Computation**: +- After `git add .`, the patch size is computed using `git diff --cached` +- The total byte count of the unified diff output is compared against `MAX_PATCH_SIZE` +- If the patch exceeds the limit, the push is aborted with an error message indicating the actual vs. allowed size + +**Error message format**: +``` +Patch size (N KB) exceeds maximum allowed size (M KB). Reduce the number or size of changes, or increase max-patch-size. +``` + +**Configuration example**: +```yaml +tools: + repo-memory: + max-patch-size: 51200 # 50 KB (default: 10240 = 10 KB) +``` + +### 6. Campaign Mode Validation When `campaign-id` is set with `memory-id: campaigns`: From f6cccfb0752557794cc2a8daf91fd8b9464c5614 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 13:54:03 +0000 Subject: [PATCH 3/5] Reduce max-patch-size maximum from 100MB to 100KB (102400 bytes) Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- docs/src/content/docs/reference/repo-memory.md | 2 +- pkg/workflow/repo_memory.go | 6 +++--- pkg/workflow/repo_memory_test.go | 18 +++++++++--------- scratchpad/repo-memory.md | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/src/content/docs/reference/repo-memory.md b/docs/src/content/docs/reference/repo-memory.md index d4a2c21c974..9694bf2531e 100644 --- a/docs/src/content/docs/reference/repo-memory.md +++ b/docs/src/content/docs/reference/repo-memory.md @@ -41,7 +41,7 @@ tools: **File Type Restrictions**: Use `allowed-extensions` to restrict which file types can be stored (default: empty/all files allowed). When specified, only files with listed extensions (e.g., `[".json", ".txt", ".md"]`) can be saved. Files with disallowed extensions will trigger validation failures. -**Patch Size Limit**: Use `max-patch-size` to limit the total size of changes in a single push (default: 10KB). The total size of the git diff (all staged changes combined) must not exceed this value. If it does, the push is rejected with an error. Use this to prevent large unintentional memory updates. +**Patch Size Limit**: Use `max-patch-size` to limit the total size of changes in a single push (default: 10KB, max: 100KB). The total size of the git diff (all staged changes combined) must not exceed this value. If it does, the push is rejected with an error. Use this to prevent large unintentional memory updates. **Note**: File glob patterns must include the full branch path structure. For branch `memory/custom-agent-for-aw`, use patterns like `memory/custom-agent-for-aw/*.json` to match files stored at that path within the branch. diff --git a/pkg/workflow/repo_memory.go b/pkg/workflow/repo_memory.go index 991f794696c..944a742ca99 100644 --- a/pkg/workflow/repo_memory.go +++ b/pkg/workflow/repo_memory.go @@ -50,7 +50,7 @@ type RepoMemoryEntry struct { FileGlob []string `yaml:"file-glob,omitempty"` // file glob patterns for allowed files MaxFileSize int `yaml:"max-file-size,omitempty"` // maximum size per file in bytes (default: 10KB) MaxFileCount int `yaml:"max-file-count,omitempty"` // maximum file count per commit (default: 100) - MaxPatchSize int `yaml:"max-patch-size,omitempty"` // maximum total patch size in bytes (default: 10KB) + MaxPatchSize int `yaml:"max-patch-size,omitempty"` // maximum total patch size in bytes (default: 10KB, max: 100KB) Description string `yaml:"description,omitempty"` // optional description for this memory CreateOrphan bool `yaml:"create-orphan,omitempty"` // create orphaned branch if missing (default: true) AllowedExtensions []string `yaml:"allowed-extensions,omitempty"` // allowed file extensions (default: [".json", ".jsonl", ".txt", ".md", ".csv"]) @@ -283,7 +283,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry.MaxPatchSize = int(sizeUint64) } // Validate max-patch-size bounds - if err := validateIntRange(entry.MaxPatchSize, 1, 104857600, "max-patch-size"); err != nil { + if err := validateIntRange(entry.MaxPatchSize, 1, 102400, "max-patch-size"); err != nil { return nil, err } } @@ -424,7 +424,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry.MaxPatchSize = int(sizeUint64) } // Validate max-patch-size bounds - if err := validateIntRange(entry.MaxPatchSize, 1, 104857600, "max-patch-size"); err != nil { + if err := validateIntRange(entry.MaxPatchSize, 1, 102400, "max-patch-size"); err != nil { return nil, err } } diff --git a/pkg/workflow/repo_memory_test.go b/pkg/workflow/repo_memory_test.go index 2ae7ab40065..ea047305e37 100644 --- a/pkg/workflow/repo_memory_test.go +++ b/pkg/workflow/repo_memory_test.go @@ -682,8 +682,8 @@ func TestRepoMemoryMaxPatchSizeValidation(t *testing.T) { wantError: false, }, { - name: "valid maximum size (104857600 bytes)", - maxPatchSize: 104857600, + name: "valid maximum size (102400 bytes = 100KB)", + maxPatchSize: 102400, wantError: false, }, { @@ -700,19 +700,19 @@ func TestRepoMemoryMaxPatchSizeValidation(t *testing.T) { name: "invalid zero size", maxPatchSize: 0, wantError: true, - errorText: "max-patch-size must be between 1 and 104857600, got 0", + errorText: "max-patch-size must be between 1 and 102400, got 0", }, { name: "invalid negative size", maxPatchSize: -1, wantError: true, - errorText: "max-patch-size must be between 1 and 104857600, got -1", + errorText: "max-patch-size must be between 1 and 102400, got -1", }, { name: "invalid size exceeds maximum", - maxPatchSize: 104857601, + maxPatchSize: 102401, wantError: true, - errorText: "max-patch-size must be between 1 and 104857600, got 104857601", + errorText: "max-patch-size must be between 1 and 102400, got 102401", }, } @@ -762,13 +762,13 @@ func TestRepoMemoryMaxPatchSizeValidationArray(t *testing.T) { name: "invalid size in array (zero)", maxPatchSize: 0, wantError: true, - errorText: "max-patch-size must be between 1 and 104857600, got 0", + errorText: "max-patch-size must be between 1 and 102400, got 0", }, { name: "invalid size in array (exceeds max)", - maxPatchSize: 104857601, + maxPatchSize: 102401, wantError: true, - errorText: "max-patch-size must be between 1 and 104857600, got 104857601", + errorText: "max-patch-size must be between 1 and 102400, got 102401", }, } diff --git a/scratchpad/repo-memory.md b/scratchpad/repo-memory.md index 832a7fe7657..d48af1bf8f5 100644 --- a/scratchpad/repo-memory.md +++ b/scratchpad/repo-memory.md @@ -234,7 +234,7 @@ tools: # file-glob: string[] (default: all files) # max-file-size: int (default: 10240, max: 104857600) # max-file-count: int (default: 100, max: 1000) - # max-patch-size: int (default: 10240, max: 104857600) + # max-patch-size: int (default: 10240, max: 102400) # description: string (optional) # create-orphan: boolean (default: true) # campaign-id: string (optional) @@ -248,7 +248,7 @@ tools: # file-glob: string[] (default: all files) # max-file-size: int (default: 10240, max: 104857600) # max-file-count: int (default: 100, max: 1000) - # max-patch-size: int (default: 10240, max: 104857600) + # max-patch-size: int (default: 10240, max: 102400) # description: string (optional) # create-orphan: boolean (default: true) # campaign-id: string (optional) @@ -383,7 +383,7 @@ file-glob: The total size of all changes (git diff) in a single repo-memory push MUST not exceed the configured maximum patch size. - **Minimum**: 1 byte -- **Maximum**: 104857600 bytes (100 MB) +- **Maximum**: 102400 bytes (100 KB) - **Default**: 10240 bytes (10 KB) - **Configuration**: `max-patch-size` (in bytes) - Validated during config parsing (Go layer) From 84197c24e248b28a45326286bb9c302a4f6e88de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:00:23 +0000 Subject: [PATCH 4/5] Fix patch size error messages and update docs with correct limits Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/push_repo_memory.cjs | 6 +++--- docs/src/content/docs/reference/repo-memory.md | 2 +- .../content/docs/reference/safe-outputs-specification.md | 2 +- scratchpad/repo-memory.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/actions/setup/js/push_repo_memory.cjs b/actions/setup/js/push_repo_memory.cjs index 768e013f537..2905179b5b6 100644 --- a/actions/setup/js/push_repo_memory.cjs +++ b/actions/setup/js/push_repo_memory.cjs @@ -345,10 +345,10 @@ async function main() { const patchContent = execGitSync(["diff", "--cached"], { stdio: "pipe" }); const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); const patchSizeKb = Math.ceil(patchSizeBytes / 1024); - const maxPatchSizeKb = Math.ceil(maxPatchSize / 1024); - core.info(`Patch size: ${patchSizeKb} KB (maximum allowed: ${maxPatchSizeKb} KB)`); + const maxPatchSizeKb = Math.floor(maxPatchSize / 1024); + core.info(`Patch size: ${patchSizeKb} KB (${patchSizeBytes} bytes) (maximum allowed: ${maxPatchSizeKb} KB (${maxPatchSize} bytes))`); if (patchSizeBytes > maxPatchSize) { - core.setFailed(`Patch size (${patchSizeKb} KB) exceeds maximum allowed size (${maxPatchSizeKb} KB). Reduce the number or size of changes, or increase max-patch-size.`); + core.setFailed(`Patch size (${patchSizeKb} KB, ${patchSizeBytes} bytes) exceeds maximum allowed size (${maxPatchSizeKb} KB, ${maxPatchSize} bytes). Reduce the number or size of changes, or increase max-patch-size.`); return; } } catch (error) { diff --git a/docs/src/content/docs/reference/repo-memory.md b/docs/src/content/docs/reference/repo-memory.md index 9694bf2531e..47bf7f5116d 100644 --- a/docs/src/content/docs/reference/repo-memory.md +++ b/docs/src/content/docs/reference/repo-memory.md @@ -30,7 +30,7 @@ tools: file-glob: ["memory/custom-agent-for-aw/*.md", "memory/custom-agent-for-aw/*.json"] max-file-size: 1048576 # 1MB (default 10KB) max-file-count: 50 # default 100 - max-patch-size: 51200 # 50KB (default 10KB) + max-patch-size: 102400 # 100KB max (default 10KB) target-repo: "owner/repository" create-orphan: true # default allowed-extensions: [".json", ".txt", ".md"] # Restrict file types (default: empty/all files allowed) diff --git a/docs/src/content/docs/reference/safe-outputs-specification.md b/docs/src/content/docs/reference/safe-outputs-specification.md index 9d553ed2c19..fdfaeb727d4 100644 --- a/docs/src/content/docs/reference/safe-outputs-specification.md +++ b/docs/src/content/docs/reference/safe-outputs-specification.md @@ -2596,7 +2596,7 @@ This section provides complete definitions for all remaining safe output types. **Notes**: - Requires `contents: write` for git push operations -- Enforces maximum patch size limit (default: 1024 KB) +- Enforces maximum patch size limit (default: 10 KB, range: 1–100 KB) - Validates changes don't exceed size limits before pushing --- diff --git a/scratchpad/repo-memory.md b/scratchpad/repo-memory.md index d48af1bf8f5..422b28c9fc7 100644 --- a/scratchpad/repo-memory.md +++ b/scratchpad/repo-memory.md @@ -396,7 +396,7 @@ The total size of all changes (git diff) in a single repo-memory push MUST not e **Error message format**: ``` -Patch size (N KB) exceeds maximum allowed size (M KB). Reduce the number or size of changes, or increase max-patch-size. +Patch size (N KB, X bytes) exceeds maximum allowed size (M KB, Y bytes). Reduce the number or size of changes, or increase max-patch-size. ``` **Configuration example**: From e341e2f8fb8b21dbbf51385d79634f958ed1113e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 14:28:57 +0000 Subject: [PATCH 5/5] Add constants, 20% overflow allowance, prompt docs, and multi-line YAML fix for max-patch-size Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../agent-performance-analyzer.lock.yml | 8 +---- .github/workflows/audit-workflows.lock.yml | 8 +---- .../workflows/chroma-issue-indexer.lock.yml | 11 ++----- .../workflows/code-scanning-fixer.lock.yml | 3 +- .../workflows/copilot-agent-analysis.lock.yml | 8 +---- .../copilot-cli-deep-research.lock.yml | 8 +---- .../copilot-pr-nlp-analysis.lock.yml | 8 +---- .../copilot-pr-prompt-analysis.lock.yml | 8 +---- .../copilot-session-insights.lock.yml | 8 +---- .../workflows/daily-cli-performance.lock.yml | 8 +---- .github/workflows/daily-code-metrics.lock.yml | 8 +---- .../daily-copilot-token-report.lock.yml | 8 +---- .github/workflows/daily-news.lock.yml | 8 +---- .../daily-testify-uber-super-expert.lock.yml | 8 +---- .github/workflows/deep-report.lock.yml | 8 +---- .github/workflows/delight.lock.yml | 8 +---- .../workflows/discussion-task-miner.lock.yml | 8 +---- .github/workflows/firewall-escape.lock.yml | 7 +---- .github/workflows/metrics-collector.lock.yml | 8 +---- .github/workflows/pr-triage-agent.lock.yml | 8 +---- .../workflows/repo-audit-analyzer.lock.yml | 11 ++----- .../repository-quality-improver.lock.yml | 11 ++----- .../workflows/security-compliance.lock.yml | 8 +---- .../workflow-health-manager.lock.yml | 8 +---- actions/setup/js/push_repo_memory.cjs | 11 +++++-- pkg/workflow/compiler_yaml_helpers.go | 12 ++++++- pkg/workflow/repo_memory.go | 31 ++++++++++++------- pkg/workflow/repo_memory_prompt.go | 5 ++- 28 files changed, 69 insertions(+), 185 deletions(-) diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index 34e0104548c..3b2c548a249 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -179,13 +179,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/meta-orchestrators' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: ** -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: **\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: '' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 6b015c4440b..7c77693594c 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -192,13 +192,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/audit-workflows' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/audit-workflows/*.json, memory/audit-workflows/*.jsonl, memory/audit-workflows/*.csv, memory/audit-workflows/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/audit-workflows/*.json, memory/audit-workflows/*.jsonl, memory/audit-workflows/*.csv, memory/audit-workflows/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical audit data and patterns' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/chroma-issue-indexer.lock.yml b/.github/workflows/chroma-issue-indexer.lock.yml index 9b7b95b5cd5..271714376d6 100644 --- a/.github/workflows/chroma-issue-indexer.lock.yml +++ b/.github/workflows/chroma-issue-indexer.lock.yml @@ -162,15 +162,8 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_ALLOWED_EXTENSIONS: '' - GH_AW_CACHE_EXAMPLES: '- `/tmp/gh-aw/cache-memory-chroma/notes.txt` - general notes and observations -- `/tmp/gh-aw/cache-memory-chroma/notes.md` - markdown formatted notes -- `/tmp/gh-aw/cache-memory-chroma/preferences.json` - user preferences and settings -- `/tmp/gh-aw/cache-memory-chroma/history.jsonl` - activity history in JSON Lines format -- `/tmp/gh-aw/cache-memory-chroma/data.csv` - tabular data -- `/tmp/gh-aw/cache-memory-chroma/state/` - organized state files in subdirectories (with allowed file types) -' - GH_AW_CACHE_LIST: '- **chroma**: `/tmp/gh-aw/cache-memory-chroma/` - Persistent storage for Chroma vector database -' + GH_AW_CACHE_EXAMPLES: "- `/tmp/gh-aw/cache-memory-chroma/notes.txt` - general notes and observations\n- `/tmp/gh-aw/cache-memory-chroma/notes.md` - markdown formatted notes\n- `/tmp/gh-aw/cache-memory-chroma/preferences.json` - user preferences and settings\n- `/tmp/gh-aw/cache-memory-chroma/history.jsonl` - activity history in JSON Lines format\n- `/tmp/gh-aw/cache-memory-chroma/data.csv` - tabular data\n- `/tmp/gh-aw/cache-memory-chroma/state/` - organized state files in subdirectories (with allowed file types)\n" + GH_AW_CACHE_LIST: "- **chroma**: `/tmp/gh-aw/cache-memory-chroma/` - Persistent storage for Chroma vector database\n" GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml index ae75e256a39..93cded9acac 100644 --- a/.github/workflows/code-scanning-fixer.lock.yml +++ b/.github/workflows/code-scanning-fixer.lock.yml @@ -177,8 +177,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_ALLOWED_EXTENSIONS: '' - GH_AW_MEMORY_LIST: '- **campaigns**: `/tmp/gh-aw/repo-memory/campaigns/` (branch: `memory/campaigns`) -' + GH_AW_MEMORY_LIST: "- **campaigns**: `/tmp/gh-aw/repo-memory/campaigns/` (branch: `memory/campaigns`)\n" GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} with: script: | diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index b9cdc245cba..a0eb4e3c05f 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -194,13 +194,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/copilot-agent-analysis' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/copilot-agent-analysis/*.json, memory/copilot-agent-analysis/*.jsonl, memory/copilot-agent-analysis/*.csv, memory/copilot-agent-analysis/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/copilot-agent-analysis/*.json, memory/copilot-agent-analysis/*.jsonl, memory/copilot-agent-analysis/*.csv, memory/copilot-agent-analysis/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical agent performance metrics' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml index 50f2ed1426d..f0fee07c5d0 100644 --- a/.github/workflows/copilot-cli-deep-research.lock.yml +++ b/.github/workflows/copilot-cli-deep-research.lock.yml @@ -180,13 +180,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/copilot-cli-research' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/copilot-cli-research/*.json, memory/copilot-cli-research/*.md -- **Max File Size**: 204800 bytes (0.20 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/copilot-cli-research/*.json, memory/copilot-cli-research/*.md\n- **Max File Size**: 204800 bytes (0.20 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Copilot CLI research notes and analysis history' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index e41d41b0f95..4c0da1ab6fa 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -200,13 +200,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/nlp-analysis' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/nlp-analysis/*.json, memory/nlp-analysis/*.jsonl, memory/nlp-analysis/*.csv, memory/nlp-analysis/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/nlp-analysis/*.json, memory/nlp-analysis/*.jsonl, memory/nlp-analysis/*.csv, memory/nlp-analysis/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical NLP analysis results' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index 15f0eac6062..5b63bf7369d 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -195,13 +195,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/prompt-analysis' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/prompt-analysis/*.json, memory/prompt-analysis/*.jsonl, memory/prompt-analysis/*.csv, memory/prompt-analysis/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/prompt-analysis/*.json, memory/prompt-analysis/*.jsonl, memory/prompt-analysis/*.csv, memory/prompt-analysis/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical prompt pattern analysis' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index 11931a23cb9..f9260d4309f 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -208,13 +208,7 @@ jobs: GH_AW_GITHUB_WORKFLOW: ${{ github.workflow }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/session-insights' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/session-insights/*.json, memory/session-insights/*.jsonl, memory/session-insights/*.csv, memory/session-insights/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/session-insights/*.json, memory/session-insights/*.jsonl, memory/session-insights/*.csv, memory/session-insights/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical session analysis data' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml index 46f3a3624a5..7e59313c249 100644 --- a/.github/workflows/daily-cli-performance.lock.yml +++ b/.github/workflows/daily-cli-performance.lock.yml @@ -186,13 +186,7 @@ jobs: GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/cli-performance' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/cli-performance/*.json, memory/cli-performance/*.jsonl, memory/cli-performance/*.txt -- **Max File Size**: 512000 bytes (0.49 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/cli-performance/*.json, memory/cli-performance/*.jsonl, memory/cli-performance/*.txt\n- **Max File Size**: 512000 bytes (0.49 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical CLI compilation performance benchmark results' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index cf558f77151..d4dbf117b89 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -191,13 +191,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'daily/daily-code-metrics' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: *.json, *.jsonl, *.csv, *.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: *.json, *.jsonl, *.csv, *.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical code quality and health metrics' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml index de9c6a2715d..6bfb8a5f3ec 100644 --- a/.github/workflows/daily-copilot-token-report.lock.yml +++ b/.github/workflows/daily-copilot-token-report.lock.yml @@ -188,13 +188,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/token-metrics' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/token-metrics/*.json, memory/token-metrics/*.jsonl, memory/token-metrics/*.csv, memory/token-metrics/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/token-metrics/*.json, memory/token-metrics/*.jsonl, memory/token-metrics/*.csv, memory/token-metrics/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical token consumption and cost data' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index aa73210c66e..b80ef493dad 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -198,13 +198,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/daily-news' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/daily-news/*.json, memory/daily-news/*.jsonl, memory/daily-news/*.csv, memory/daily-news/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/daily-news/*.json, memory/daily-news/*.jsonl, memory/daily-news/*.csv, memory/daily-news/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Historical news digest data' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml index 409355ee80b..35f703bda7a 100644 --- a/.github/workflows/daily-testify-uber-super-expert.lock.yml +++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml @@ -190,13 +190,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/testify-expert' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/testify-expert/*.json, memory/testify-expert/*.txt -- **Max File Size**: 51200 bytes (0.05 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/testify-expert/*.json, memory/testify-expert/*.txt\n- **Max File Size**: 51200 bytes (0.05 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Tracks processed test files to avoid duplicates' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index 945b4cc1821..890163b0e0d 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -190,13 +190,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/deep-report' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/deep-report/*.md -- **Max File Size**: 1048576 bytes (1.00 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/deep-report/*.md\n- **Max File Size**: 1048576 bytes (1.00 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Long-term insights, patterns, and trend data' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml index 3de45083e2b..52745fb6eb2 100644 --- a/.github/workflows/delight.lock.yml +++ b/.github/workflows/delight.lock.yml @@ -183,13 +183,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/delight' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/delight/*.json, memory/delight/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/delight/*.json, memory/delight/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Track delight findings and historical patterns' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml index cac3afcff7b..deed433c861 100644 --- a/.github/workflows/discussion-task-miner.lock.yml +++ b/.github/workflows/discussion-task-miner.lock.yml @@ -181,13 +181,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/discussion-task-miner' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/discussion-task-miner/*.json, memory/discussion-task-miner/*.md -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/discussion-task-miner/*.json, memory/discussion-task-miner/*.md\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Track processed discussions and extracted tasks' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml index 7816ed5bc14..1b1e6fb520c 100644 --- a/.github/workflows/firewall-escape.lock.yml +++ b/.github/workflows/firewall-escape.lock.yml @@ -197,12 +197,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/firewall-escape' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Max File Size**: 524288 bytes (0.50 MB) per file -- **Max File Count**: 50 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Max File Size**: 524288 bytes (0.50 MB) per file\n- **Max File Count**: 50 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: ' Persistent storage for firewall escape attempt history and strategies' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/metrics-collector.lock.yml b/.github/workflows/metrics-collector.lock.yml index 17f2c4dda93..d56fc35fe81 100644 --- a/.github/workflows/metrics-collector.lock.yml +++ b/.github/workflows/metrics-collector.lock.yml @@ -168,13 +168,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/meta-orchestrators' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: metrics/** -- **Max File Size**: 10240 bytes (0.01 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: metrics/**\n- **Max File Size**: 10240 bytes (0.01 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: '' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml index cbc4ed01fd3..aa2762caf08 100644 --- a/.github/workflows/pr-triage-agent.lock.yml +++ b/.github/workflows/pr-triage-agent.lock.yml @@ -171,13 +171,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/pr-triage' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: ** -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: **\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: '' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/repo-audit-analyzer.lock.yml b/.github/workflows/repo-audit-analyzer.lock.yml index 3efd2361b65..9ec1a819bb3 100644 --- a/.github/workflows/repo-audit-analyzer.lock.yml +++ b/.github/workflows/repo-audit-analyzer.lock.yml @@ -174,15 +174,8 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_ALLOWED_EXTENSIONS: '' - GH_AW_CACHE_EXAMPLES: '- `/tmp/gh-aw/cache-memory-repo-audits/notes.txt` - general notes and observations -- `/tmp/gh-aw/cache-memory-repo-audits/notes.md` - markdown formatted notes -- `/tmp/gh-aw/cache-memory-repo-audits/preferences.json` - user preferences and settings -- `/tmp/gh-aw/cache-memory-repo-audits/history.jsonl` - activity history in JSON Lines format -- `/tmp/gh-aw/cache-memory-repo-audits/data.csv` - tabular data -- `/tmp/gh-aw/cache-memory-repo-audits/state/` - organized state files in subdirectories (with allowed file types) -' - GH_AW_CACHE_LIST: '- **repo-audits**: `/tmp/gh-aw/cache-memory-repo-audits/` -' + GH_AW_CACHE_EXAMPLES: "- `/tmp/gh-aw/cache-memory-repo-audits/notes.txt` - general notes and observations\n- `/tmp/gh-aw/cache-memory-repo-audits/notes.md` - markdown formatted notes\n- `/tmp/gh-aw/cache-memory-repo-audits/preferences.json` - user preferences and settings\n- `/tmp/gh-aw/cache-memory-repo-audits/history.jsonl` - activity history in JSON Lines format\n- `/tmp/gh-aw/cache-memory-repo-audits/data.csv` - tabular data\n- `/tmp/gh-aw/cache-memory-repo-audits/state/` - organized state files in subdirectories (with allowed file types)\n" + GH_AW_CACHE_LIST: "- **repo-audits**: `/tmp/gh-aw/cache-memory-repo-audits/`\n" GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 30763e0f3c3..414a853f0b2 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -173,15 +173,8 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_ALLOWED_EXTENSIONS: '' - GH_AW_CACHE_EXAMPLES: '- `/tmp/gh-aw/cache-memory-focus-areas/notes.txt` - general notes and observations -- `/tmp/gh-aw/cache-memory-focus-areas/notes.md` - markdown formatted notes -- `/tmp/gh-aw/cache-memory-focus-areas/preferences.json` - user preferences and settings -- `/tmp/gh-aw/cache-memory-focus-areas/history.jsonl` - activity history in JSON Lines format -- `/tmp/gh-aw/cache-memory-focus-areas/data.csv` - tabular data -- `/tmp/gh-aw/cache-memory-focus-areas/state/` - organized state files in subdirectories (with allowed file types) -' - GH_AW_CACHE_LIST: '- **focus-areas**: `/tmp/gh-aw/cache-memory-focus-areas/` -' + GH_AW_CACHE_EXAMPLES: "- `/tmp/gh-aw/cache-memory-focus-areas/notes.txt` - general notes and observations\n- `/tmp/gh-aw/cache-memory-focus-areas/notes.md` - markdown formatted notes\n- `/tmp/gh-aw/cache-memory-focus-areas/preferences.json` - user preferences and settings\n- `/tmp/gh-aw/cache-memory-focus-areas/history.jsonl` - activity history in JSON Lines format\n- `/tmp/gh-aw/cache-memory-focus-areas/data.csv` - tabular data\n- `/tmp/gh-aw/cache-memory-focus-areas/state/` - organized state files in subdirectories (with allowed file types)\n" + GH_AW_CACHE_LIST: "- **focus-areas**: `/tmp/gh-aw/cache-memory-focus-areas/`\n" GH_AW_GITHUB_ACTOR: ${{ github.actor }} GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml index cd865b6f59f..21f372d9d36 100644 --- a/.github/workflows/security-compliance.lock.yml +++ b/.github/workflows/security-compliance.lock.yml @@ -201,13 +201,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/campaigns' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: memory/campaigns/security-compliance-*/** -- **Max File Size**: 10240 bytes (0.01 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: memory/campaigns/security-compliance-*/**\n- **Max File Size**: 10240 bytes (0.01 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: '' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml index d8997816ff5..2094ceae9b7 100644 --- a/.github/workflows/workflow-health-manager.lock.yml +++ b/.github/workflows/workflow-health-manager.lock.yml @@ -179,13 +179,7 @@ jobs: GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MEMORY_BRANCH_NAME: 'memory/meta-orchestrators' - GH_AW_MEMORY_CONSTRAINTS: ' - -**Constraints:** -- **Allowed Files**: Only files matching patterns: ** -- **Max File Size**: 102400 bytes (0.10 MB) per file -- **Max File Count**: 100 files per commit -' + GH_AW_MEMORY_CONSTRAINTS: "\n\n**Constraints:**\n- **Allowed Files**: Only files matching patterns: **\n- **Max File Size**: 102400 bytes (0.10 MB) per file\n- **Max File Count**: 100 files per commit\n- **Max Patch Size**: 10240 bytes (10 KB) total per push (max: 100 KB)\n" GH_AW_MEMORY_DESCRIPTION: '' GH_AW_MEMORY_DIR: '/tmp/gh-aw/repo-memory/default/' GH_AW_MEMORY_TARGET_REPO: ' of the current repository' diff --git a/actions/setup/js/push_repo_memory.cjs b/actions/setup/js/push_repo_memory.cjs index 2905179b5b6..3dc556f41e6 100644 --- a/actions/setup/js/push_repo_memory.cjs +++ b/actions/setup/js/push_repo_memory.cjs @@ -346,9 +346,14 @@ async function main() { const patchSizeBytes = Buffer.byteLength(patchContent, "utf8"); const patchSizeKb = Math.ceil(patchSizeBytes / 1024); const maxPatchSizeKb = Math.floor(maxPatchSize / 1024); - core.info(`Patch size: ${patchSizeKb} KB (${patchSizeBytes} bytes) (maximum allowed: ${maxPatchSizeKb} KB (${maxPatchSize} bytes))`); - if (patchSizeBytes > maxPatchSize) { - core.setFailed(`Patch size (${patchSizeKb} KB, ${patchSizeBytes} bytes) exceeds maximum allowed size (${maxPatchSizeKb} KB, ${maxPatchSize} bytes). Reduce the number or size of changes, or increase max-patch-size.`); + // Allow 20% overhead to account for git diff format (headers, context lines, etc.) + const effectiveMaxPatchSize = Math.floor(maxPatchSize * 1.2); + const effectiveMaxPatchSizeKb = Math.floor(effectiveMaxPatchSize / 1024); + core.info(`Patch size: ${patchSizeKb} KB (${patchSizeBytes} bytes) (configured limit: ${maxPatchSizeKb} KB (${maxPatchSize} bytes), effective with 20% overhead: ${effectiveMaxPatchSizeKb} KB (${effectiveMaxPatchSize} bytes))`); + if (patchSizeBytes > effectiveMaxPatchSize) { + core.setFailed( + `Patch size (${patchSizeKb} KB, ${patchSizeBytes} bytes) exceeds maximum allowed size (${effectiveMaxPatchSizeKb} KB, ${effectiveMaxPatchSize} bytes, configured limit: ${maxPatchSizeKb} KB with 20% overhead allowance). Reduce the number or size of changes, or increase max-patch-size.` + ); return; } } catch (error) { diff --git a/pkg/workflow/compiler_yaml_helpers.go b/pkg/workflow/compiler_yaml_helpers.go index fca41dfde08..38250cd5b0d 100644 --- a/pkg/workflow/compiler_yaml_helpers.go +++ b/pkg/workflow/compiler_yaml_helpers.go @@ -111,7 +111,17 @@ func generatePlaceholderSubstitutionStep(yaml *strings.Builder, expressionMappin if (strings.HasPrefix(content, "'") && strings.HasSuffix(content, "'")) || (strings.HasPrefix(content, "\"") && strings.HasSuffix(content, "\"")) { // Static value - output directly without ${{ }} wrapper - fmt.Fprintf(yaml, indent+" %s: %s\n", mapping.EnvVar, content) + // Check if inner value is multi-line; if so use a YAML double-quoted scalar + // with escaped newlines to avoid invalid YAML. + innerValue := content[1 : len(content)-1] + if strings.Contains(innerValue, "\n") { + escaped := strings.ReplaceAll(innerValue, `\`, `\\`) + escaped = strings.ReplaceAll(escaped, `"`, `\"`) + escaped = strings.ReplaceAll(escaped, "\n", `\n`) + fmt.Fprintf(yaml, indent+" %s: \"%s\"\n", mapping.EnvVar, escaped) + } else { + fmt.Fprintf(yaml, indent+" %s: %s\n", mapping.EnvVar, content) + } } else { // GitHub expression - wrap in ${{ }} fmt.Fprintf(yaml, indent+" %s: ${{ %s }}\n", mapping.EnvVar, content) diff --git a/pkg/workflow/repo_memory.go b/pkg/workflow/repo_memory.go index 944a742ca99..1fb70a12810 100644 --- a/pkg/workflow/repo_memory.go +++ b/pkg/workflow/repo_memory.go @@ -30,6 +30,13 @@ import ( var repoMemoryLog = logger.New("workflow:repo_memory") +const ( + // defaultRepoMemoryMaxPatchSize is the default maximum total patch size in bytes (10KB). + defaultRepoMemoryMaxPatchSize = 10240 + // maxRepoMemoryPatchSize is the maximum allowed value for max-patch-size (100KB). + maxRepoMemoryPatchSize = 102400 +) + // Pre-compiled regexes for performance (avoid recompilation in hot paths) var ( // branchPrefixValidPattern matches valid branch prefix characters (alphanumeric, hyphens, underscores) @@ -131,7 +138,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), MaxFileSize: 10240, // 10KB MaxFileCount: 100, - MaxPatchSize: 10240, // 10KB + MaxPatchSize: defaultRepoMemoryMaxPatchSize, // 10KB CreateOrphan: true, AllowedExtensions: constants.DefaultAllowedMemoryExtensions, }, @@ -150,7 +157,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), MaxFileSize: 10240, // 10KB MaxFileCount: 100, - MaxPatchSize: 10240, // 10KB + MaxPatchSize: defaultRepoMemoryMaxPatchSize, // 10KB CreateOrphan: true, AllowedExtensions: constants.DefaultAllowedMemoryExtensions, }, @@ -186,10 +193,10 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID for _, item := range memoryArray { if memoryMap, ok := item.(map[string]any); ok { entry := RepoMemoryEntry{ - MaxFileSize: 10240, // 10KB default - MaxFileCount: 100, // 100 files default - MaxPatchSize: 10240, // 10KB default - CreateOrphan: true, // create orphan by default + MaxFileSize: 10240, // 10KB default + MaxFileCount: 100, // 100 files default + MaxPatchSize: defaultRepoMemoryMaxPatchSize, // 10KB default + CreateOrphan: true, // create orphan by default } // ID is required for array notation @@ -283,7 +290,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry.MaxPatchSize = int(sizeUint64) } // Validate max-patch-size bounds - if err := validateIntRange(entry.MaxPatchSize, 1, 102400, "max-patch-size"); err != nil { + if err := validateIntRange(entry.MaxPatchSize, 1, maxRepoMemoryPatchSize, "max-patch-size"); err != nil { return nil, err } } @@ -349,10 +356,10 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry := RepoMemoryEntry{ ID: "default", BranchName: generateDefaultBranchName(defaultMemoryBranchID(), config.BranchPrefix), - MaxFileSize: 10240, // 10KB default - MaxFileCount: 100, // 100 files default - MaxPatchSize: 10240, // 10KB default - CreateOrphan: true, // create orphan by default + MaxFileSize: 10240, // 10KB default + MaxFileCount: 100, // 100 files default + MaxPatchSize: defaultRepoMemoryMaxPatchSize, // 10KB default + CreateOrphan: true, // create orphan by default } // Parse target-repo @@ -424,7 +431,7 @@ func (c *Compiler) extractRepoMemoryConfig(toolsConfig *ToolsConfig, workflowID entry.MaxPatchSize = int(sizeUint64) } // Validate max-patch-size bounds - if err := validateIntRange(entry.MaxPatchSize, 1, 102400, "max-patch-size"); err != nil { + if err := validateIntRange(entry.MaxPatchSize, 1, maxRepoMemoryPatchSize, "max-patch-size"); err != nil { return nil, err } } diff --git a/pkg/workflow/repo_memory_prompt.go b/pkg/workflow/repo_memory_prompt.go index 39eec0793aa..8856d2b8fcf 100644 --- a/pkg/workflow/repo_memory_prompt.go +++ b/pkg/workflow/repo_memory_prompt.go @@ -40,7 +40,7 @@ func buildRepoMemoryPromptSection(config *RepoMemoryConfig) *PromptSection { // The value is either "\n" (blank line only) or "\n\n**Constraints:**\n...\n" // so that the template line __GH_AW_MEMORY_CONSTRAINTS__\nExamples... renders correctly. constraintsText := "\n" - if len(memory.FileGlob) > 0 || memory.MaxFileSize > 0 || memory.MaxFileCount > 0 { + if len(memory.FileGlob) > 0 || memory.MaxFileSize > 0 || memory.MaxFileCount > 0 || memory.MaxPatchSize > 0 { var constraints strings.Builder constraints.WriteString("\n\n**Constraints:**\n") if len(memory.FileGlob) > 0 { @@ -52,6 +52,9 @@ func buildRepoMemoryPromptSection(config *RepoMemoryConfig) *PromptSection { if memory.MaxFileCount > 0 { fmt.Fprintf(&constraints, "- **Max File Count**: %d files per commit\n", memory.MaxFileCount) } + if memory.MaxPatchSize > 0 { + fmt.Fprintf(&constraints, "- **Max Patch Size**: %d bytes (%d KB) total per push (max: %d KB)\n", memory.MaxPatchSize, memory.MaxPatchSize/1024, maxRepoMemoryPatchSize/1024) + } constraintsText = constraints.String() }