From 10b75e1fbb0bfc339fc986633cf880a36b08d744 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 23 Apr 2026 14:48:00 +0000
Subject: [PATCH 1/7] chore: plan comment-memory code-fence update
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c58aea4c-9179-42ff-b29b-9bbb205e5f9b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
pkg/cli/spec_test.go | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pkg/cli/spec_test.go b/pkg/cli/spec_test.go
index c6b739b93fc..f46eabc88ec 100644
--- a/pkg/cli/spec_test.go
+++ b/pkg/cli/spec_test.go
@@ -1117,11 +1117,11 @@ func TestSpec_PublicAPI_ValidateWorkflowIntent(t *testing.T) {
// Spec: "Sets a field in frontmatter YAML"
func TestSpec_PublicAPI_UpdateFieldInFrontmatter(t *testing.T) {
tests := []struct {
- name string
- content string
- fieldName string
- fieldValue string
- wantErr bool
+ name string
+ content string
+ fieldName string
+ fieldValue string
+ wantErr bool
checkContains string
}{
{
From 66712862e6e4083df6289c9351442f2120da13f2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 23 Apr 2026 14:52:10 +0000
Subject: [PATCH 2/7] fix(comment-memory): wrap managed memory content in
six-backtick code region
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c58aea4c-9179-42ff-b29b-9bbb205e5f9b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/comment_memory.cjs | 4 +--
actions/setup/js/comment_memory.test.cjs | 2 ++
actions/setup/js/comment_memory_helpers.cjs | 29 ++++++++++++++++++-
.../setup/js/comment_memory_helpers.test.cjs | 5 ++++
.../js/setup_comment_memory_files.test.cjs | 10 +++----
5 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/actions/setup/js/comment_memory.cjs b/actions/setup/js/comment_memory.cjs
index 81889b6a90a..002693aea28 100644
--- a/actions/setup/js/comment_memory.cjs
+++ b/actions/setup/js/comment_memory.cjs
@@ -14,7 +14,7 @@ const { buildWorkflowRunUrl } = require("./workflow_metadata_helpers.cjs");
const { getTrackerID } = require("./get_tracker_id.cjs");
const { generateHistoryUrl } = require("./generate_history_link.cjs");
const { enforceCommentLimits } = require("./comment_limit_helpers.cjs");
-const { COMMENT_MEMORY_TAG, COMMENT_MEMORY_MAX_SCAN_PAGES } = require("./comment_memory_helpers.cjs");
+const { COMMENT_MEMORY_TAG, COMMENT_MEMORY_MAX_SCAN_PAGES, COMMENT_MEMORY_CODE_FENCE } = require("./comment_memory_helpers.cjs");
// Require provenance marker to avoid accidentally updating user-authored comments
// that happen to contain a matching comment-memory tag.
const MANAGED_COMMENT_PROVENANCE_MARKER = "";
const COMMENT_MEMORY_PROMPT_END_MARKER = "";
+const COMMENT_MEMORY_CODE_FENCE = "``````";
+
+function stripCommentMemoryCodeFence(content) {
+ const trimmed = String(content || "").trim();
+ if (!trimmed.startsWith(COMMENT_MEMORY_CODE_FENCE)) {
+ return trimmed;
+ }
+
+ const firstNewline = trimmed.indexOf("\n", COMMENT_MEMORY_CODE_FENCE.length);
+ if (firstNewline < 0) {
+ return trimmed;
+ }
+
+ const closingFenceStart = trimmed.lastIndexOf(`\n${COMMENT_MEMORY_CODE_FENCE}`);
+ if (closingFenceStart <= firstNewline) {
+ return trimmed;
+ }
+
+ const trailing = trimmed.slice(closingFenceStart + COMMENT_MEMORY_CODE_FENCE.length + 1).trim();
+ if (trailing.length > 0) {
+ return trimmed;
+ }
+
+ return trimmed.slice(firstNewline + 1, closingFenceStart).trim();
+}
function isSafeMemoryId(memoryId) {
if (typeof memoryId !== "string" || memoryId.length === 0 || memoryId.length > MAX_MEMORY_ID_LENGTH) {
@@ -57,7 +82,7 @@ function extractCommentMemoryEntries(commentBody, warn = () => {}) {
if (isSafeMemoryId(memoryId)) {
entries.push({
memoryId,
- content: (commentBody.slice(contentStart, closeStart) || "").trim(),
+ content: stripCommentMemoryCodeFence(commentBody.slice(contentStart, closeStart)),
});
} else {
warn(`skipping unsafe memory_id '${memoryId}'`);
@@ -99,7 +124,9 @@ module.exports = {
COMMENT_MEMORY_MAX_SCAN_EMPTY_PAGES,
COMMENT_MEMORY_PROMPT_START_MARKER,
COMMENT_MEMORY_PROMPT_END_MARKER,
+ COMMENT_MEMORY_CODE_FENCE,
isSafeMemoryId,
+ stripCommentMemoryCodeFence,
extractCommentMemoryEntries,
listCommentMemoryFiles,
resolveCommentMemoryConfig,
diff --git a/actions/setup/js/comment_memory_helpers.test.cjs b/actions/setup/js/comment_memory_helpers.test.cjs
index 0c7ef0d79a2..5b19b5ebcd6 100644
--- a/actions/setup/js/comment_memory_helpers.test.cjs
+++ b/actions/setup/js/comment_memory_helpers.test.cjs
@@ -3,6 +3,11 @@ import { extractCommentMemoryEntries, isSafeMemoryId } from "./comment_memory_he
describe("comment_memory_helpers", () => {
it("extracts managed memory entries", () => {
+ const entries = extractCommentMemoryEntries('\n``````\nhello\n``````\n');
+ expect(entries).toEqual([{ memoryId: "default", content: "hello" }]);
+ });
+
+ it("supports legacy memory entries without code fence markers", () => {
const entries = extractCommentMemoryEntries('\nhello\n');
expect(entries).toEqual([{ memoryId: "default", content: "hello" }]);
});
diff --git a/actions/setup/js/setup_comment_memory_files.test.cjs b/actions/setup/js/setup_comment_memory_files.test.cjs
index 1580880cf30..be2bf764834 100644
--- a/actions/setup/js/setup_comment_memory_files.test.cjs
+++ b/actions/setup/js/setup_comment_memory_files.test.cjs
@@ -35,7 +35,7 @@ describe("setup_comment_memory_files", () => {
it("extracts memory entries from managed comment body", async () => {
const module = await import("./setup_comment_memory_files.cjs");
- const entries = module.extractCommentMemoryEntries('\nhello\n');
+ const entries = module.extractCommentMemoryEntries('\n``````\nhello\n``````\n');
expect(entries).toEqual([{ memoryId: "default", content: "hello" }]);
});
@@ -47,7 +47,7 @@ describe("setup_comment_memory_files", () => {
listComments: vi.fn().mockResolvedValue({
data: [
{
- body: '\nSaved memory\n\nfooter',
+ body: '\n``````\nSaved memory\n``````\n\nfooter',
},
],
}),
@@ -76,7 +76,7 @@ describe("setup_comment_memory_files", () => {
});
}
if (page === 6) {
- return Promise.resolve({ data: [{ body: '\nLate memory\n' }] });
+ return Promise.resolve({ data: [{ body: '\n``````\nLate memory\n``````\n' }] });
}
return Promise.resolve({ data: [] });
});
@@ -156,7 +156,7 @@ describe("setup_comment_memory_files", () => {
})
);
const listComments = vi.fn().mockResolvedValue({
- data: [{ body: '\nCross repo memory\n' }],
+ data: [{ body: '\n``````\nCross repo memory\n``````\n' }],
});
global.github = {
rest: {
@@ -192,7 +192,7 @@ describe("setup_comment_memory_files", () => {
})
);
const listComments = vi.fn().mockResolvedValue({
- data: [{ body: '\nSame repo memory\n' }],
+ data: [{ body: '\n``````\nSame repo memory\n``````\n' }],
});
global.github = {
rest: {
From 70b6bb7f836b3b58360a21e4fad01cb257754a88 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 23 Apr 2026 14:58:06 +0000
Subject: [PATCH 3/7] refactor(comment-memory): simplify managed body template
string
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c58aea4c-9179-42ff-b29b-9bbb205e5f9b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/comment_memory.cjs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/actions/setup/js/comment_memory.cjs b/actions/setup/js/comment_memory.cjs
index 002693aea28..d4a3fb49927 100644
--- a/actions/setup/js/comment_memory.cjs
+++ b/actions/setup/js/comment_memory.cjs
@@ -45,7 +45,13 @@ function buildManagedMemoryBody(rawBody, memoryID, options) {
const openingTag = `<${COMMENT_MEMORY_TAG} id="${memoryID}">`;
const closingTag = `${COMMENT_MEMORY_TAG}>`;
core.info(`comment_memory: building managed body for memory_id='${memoryID}'`);
- let body = `${MANAGED_COMMENT_HEADER}\n\n${openingTag}\n` + `${COMMENT_MEMORY_CODE_FENCE}\n${sanitizeContent(rawBody)}\n${COMMENT_MEMORY_CODE_FENCE}\n` + `${closingTag}`;
+ let body = `${MANAGED_COMMENT_HEADER}
+
+${openingTag}
+${COMMENT_MEMORY_CODE_FENCE}
+${sanitizeContent(rawBody)}
+${COMMENT_MEMORY_CODE_FENCE}
+${closingTag}`;
const tracker = getTrackerID("markdown");
if (tracker) {
From 072d528ac37a1180223f904073e2cde85a55fc58 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 23 Apr 2026 15:01:21 +0000
Subject: [PATCH 4/7] test(comment-memory): add edge-case coverage for fenced
memory parsing
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c58aea4c-9179-42ff-b29b-9bbb205e5f9b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/comment_memory_helpers.cjs | 3 ++-
.../setup/js/comment_memory_helpers.test.cjs | 22 ++++++++++++++++++-
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/actions/setup/js/comment_memory_helpers.cjs b/actions/setup/js/comment_memory_helpers.cjs
index 1ba45c451f4..d370c857d12 100644
--- a/actions/setup/js/comment_memory_helpers.cjs
+++ b/actions/setup/js/comment_memory_helpers.cjs
@@ -29,7 +29,8 @@ function stripCommentMemoryCodeFence(content) {
return trimmed;
}
- const trailing = trimmed.slice(closingFenceStart + COMMENT_MEMORY_CODE_FENCE.length + 1).trim();
+ const closingFenceEnd = closingFenceStart + 1 + COMMENT_MEMORY_CODE_FENCE.length;
+ const trailing = trimmed.slice(closingFenceEnd).trim();
if (trailing.length > 0) {
return trimmed;
}
diff --git a/actions/setup/js/comment_memory_helpers.test.cjs b/actions/setup/js/comment_memory_helpers.test.cjs
index 5b19b5ebcd6..b58fd249c8b 100644
--- a/actions/setup/js/comment_memory_helpers.test.cjs
+++ b/actions/setup/js/comment_memory_helpers.test.cjs
@@ -1,5 +1,5 @@
import { describe, it, expect, vi } from "vitest";
-import { extractCommentMemoryEntries, isSafeMemoryId } from "./comment_memory_helpers.cjs";
+import { extractCommentMemoryEntries, isSafeMemoryId, stripCommentMemoryCodeFence } from "./comment_memory_helpers.cjs";
describe("comment_memory_helpers", () => {
it("extracts managed memory entries", () => {
@@ -12,6 +12,26 @@ describe("comment_memory_helpers", () => {
expect(entries).toEqual([{ memoryId: "default", content: "hello" }]);
});
+ it("keeps fenced text unchanged when trailing content exists after closing fence", () => {
+ const content = "``````\nhello\n``````\ntrailing";
+ expect(stripCommentMemoryCodeFence(content)).toBe(content);
+ });
+
+ it("keeps fenced text unchanged when closing fence is missing", () => {
+ const content = "``````\nhello";
+ expect(stripCommentMemoryCodeFence(content)).toBe(content);
+ });
+
+ it("keeps malformed fenced text unchanged", () => {
+ const content = "``````hello\n``````";
+ expect(stripCommentMemoryCodeFence(content)).toBe(content);
+ });
+
+ it("strips valid fenced text with extra newlines before content", () => {
+ const content = "``````\n\nhello\n``````";
+ expect(stripCommentMemoryCodeFence(content)).toBe("hello");
+ });
+
it("rejects unsafe memory IDs", () => {
const warning = vi.fn();
const entries = extractCommentMemoryEntries('\nhello\n', warning);
From 73db6af188aa4f6e88589de82273a41808494c57 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 23 Apr 2026 15:04:03 +0000
Subject: [PATCH 5/7] refactor(comment-memory): tighten fenced content parsing
guards
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c58aea4c-9179-42ff-b29b-9bbb205e5f9b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/comment_memory_helpers.cjs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/actions/setup/js/comment_memory_helpers.cjs b/actions/setup/js/comment_memory_helpers.cjs
index d370c857d12..b524a374fef 100644
--- a/actions/setup/js/comment_memory_helpers.cjs
+++ b/actions/setup/js/comment_memory_helpers.cjs
@@ -14,7 +14,10 @@ const COMMENT_MEMORY_PROMPT_END_MARKER = "";
const COMMENT_MEMORY_PROMPT_END_MARKER = "";
const COMMENT_MEMORY_CODE_FENCE = "``````";
+const ESCAPED_COMMENT_MEMORY_CODE_FENCE = COMMENT_MEMORY_CODE_FENCE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
function stripCommentMemoryCodeFence(content) {
const trimmed = typeof content === "string" ? content.trim() : "";
@@ -21,8 +22,7 @@ function stripCommentMemoryCodeFence(content) {
if (!trimmed.startsWith(COMMENT_MEMORY_CODE_FENCE)) {
return trimmed;
}
- const escapedFence = COMMENT_MEMORY_CODE_FENCE.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
- const match = trimmed.match(new RegExp(`^${escapedFence}[^\\n]*\\n([\\s\\S]*)\\n${escapedFence}$`));
+ const match = trimmed.match(new RegExp(`^${ESCAPED_COMMENT_MEMORY_CODE_FENCE}[^\\n]*\\n([\\s\\S]*)\\n${ESCAPED_COMMENT_MEMORY_CODE_FENCE}$`));
if (!match) {
return trimmed;
}