Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 100 additions & 8 deletions .github/workflows/mattpocock-skills-reviewer.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 8 additions & 29 deletions .github/workflows/mattpocock-skills-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ permissions:
contents: read
pull-requests: read
copilot-requests: write
skills:
- mattpocock/skills/diagnosing-bugs@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/tdd@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/improve-codebase-architecture@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/grill-with-docs@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/to-prd@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/codebase-design@801dca688564c529fa84f247f64472520d9ebe28
- mattpocock/skills/domain-modeling@801dca688564c529fa84f247f64472520d9ebe28

sandbox:
agent:
Expand All @@ -28,35 +36,6 @@ imports:
min-integrity: approved
- shared/otlp.md
pre-agent-steps:
- name: Upgrade gh CLI
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/install_gh_cli.sh"
GH_VERSION=$(gh --version | head -1 | grep -oP '\d+\.\d+\.\d+')
echo "gh version: ${GH_VERSION}"
REQUIRED="2.90.0"
if ! printf '%s\n%s\n' "$REQUIRED" "$GH_VERSION" | sort -V -C; then
echo "::error::gh ${GH_VERSION} is older than required ${REQUIRED} (gh skill support requires v2.90+)"
exit 1
fi
- name: Install Matt Pocock skills
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
SKILLS_DST="${RUNNER_TEMP}/gh-aw/mattpocock-skills"
mkdir -p "${SKILLS_DST}"
# Install only the skills referenced in this workflow's prompt, rather than
# all published skills, to reduce install time and network overhead.
for skill in diagnosing-bugs tdd improve-codebase-architecture grill-with-docs to-prd codebase-design domain-modeling; do
gh skill install mattpocock/skills "${skill}" --dir "${SKILLS_DST}" --force
done
SKILL_COUNT=$(find "${SKILLS_DST}" -name "SKILL.md" | wc -l)
echo "Installed ${SKILL_COUNT} skill(s):"
find "${SKILLS_DST}" -name "SKILL.md" | head -20
if [ "${SKILL_COUNT}" -eq 0 ]; then
echo "::error::No SKILL.md files found after installing mattpocock/skills"
exit 1
fi
- name: Pre-fetch PR diff
env:
GH_TOKEN: ${{ github.token }}
Expand Down
38 changes: 38 additions & 0 deletions actions/setup/js/generate_aw_info.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ async function main(core, ctx) {
awInfo.features = features;
}

const skills = parseSkillsFromEnv(core);
if (skills) {
awInfo.skills = skills;
core.info(`Configured frontmatter skills (${skills.length}): ${skills.join(", ")}`);
}

// Include aw_context when the workflow was triggered by a caller that relayed
// orchestration context via workflow inputs or repository_dispatch client payload.
// Validates JSON format and structure before populating the context key in aw_info.json.
Expand Down Expand Up @@ -218,6 +224,38 @@ async function main(core, ctx) {
}
}

/**
* Parse optional skills list from GH_AW_INFO_SKILLS.
* @param {typeof import('@actions/core')} core
* @returns {string[] | null}
*/
function parseSkillsFromEnv(core) {
const skillsEnv = process.env.GH_AW_INFO_SKILLS;
if (!skillsEnv) {
return null;
}
try {
const parsed = JSON.parse(skillsEnv);
if (!Array.isArray(parsed)) {
core.warning("GH_AW_INFO_SKILLS must be a JSON array, ignoring");
return null;
}
const skills = [];
for (const [index, value] of parsed.entries()) {
if (typeof value === "string" && value.length > 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] parseSkillsFromEnv accepts any non-empty string into aw_info.json without validating the spec format. While the Go compiler enforces the owner/repo@<40-char-sha> constraint at compile time, the env var could be set or overridden manually, and there is no test covering the warning paths (malformed JSON, non-array, non-string items).

💡 Missing tests to add in `generate_aw_info.test.cjs`
it("should warn and return null for non-array GH_AW_INFO_SKILLS", async () => {
  process.env.GH_AW_INFO_SKILLS = JSON.stringify("not-an-array");
  await main(mockCore, mockContext);
  const awInfo = JSON.parse(fs.readFileSync(awInfoPath, "utf8"));
  expect(awInfo.skills).toBeUndefined();
  expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("JSON array"));
});

it("should warn and skip non-string items in GH_AW_INFO_SKILLS", async () => {
  process.env.GH_AW_INFO_SKILLS = JSON.stringify([42, "valid/spec@" + "a".repeat(40)]);
  await main(mockCore, mockContext);
  expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("[0]"));
});

it("should warn and return null for unparseable GH_AW_INFO_SKILLS", async () => {
  process.env.GH_AW_INFO_SKILLS = "not-json";
  await main(mockCore, mockContext);
  const awInfo = JSON.parse(fs.readFileSync(awInfoPath, "utf8"));
  expect(awInfo.skills).toBeUndefined();
  expect(mockCore.warning).toHaveBeenCalledWith(expect.stringContaining("Failed to parse"));
});

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in a1e89b7. generate_aw_info.test.cjs now covers malformed JSON, non-array payloads, and non-string items for GH_AW_INFO_SKILLS.

skills.push(value);
continue;
}
core.warning(`Ignoring invalid GH_AW_INFO_SKILLS[${index}] value: ${JSON.stringify(value)}`);
}
return skills.length > 0 ? skills : null;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
core.warning(`Failed to parse GH_AW_INFO_SKILLS: ${skillsEnv} (${message})`);
return null;
}
}

core.info("Generated aw_info.json at: " + tmpPath);
core.info(JSON.stringify(awInfo, null, 2));

Expand Down
Loading
Loading