Skip to content

Commit 506b7ef

Browse files
committed
feat: add forge to PowerShell script and fix test whitespace
1. PowerShell script (create-release-packages.ps1): - Added forge agent support for Windows users - Enables `specify init --ai forge --offline` on Windows - Enhanced Generate-Commands with ExtraStripKey parameter - Added frontmatter stripping for handoffs key - Added $ARGUMENTS replacement for {{parameters}} - Implemented forge case with name field injection - Complete parity with bash script 2. Test file (test_core_pack_scaffold.py): - Removed trailing whitespace from blank lines - Cleaner diffs and no linter warnings Addresses Copilot PR feedback on both issues.
1 parent 635790d commit 506b7ef

2 files changed

Lines changed: 34 additions & 7 deletions

File tree

.github/workflows/scripts/create-release-packages.ps1

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
.PARAMETER Agents
1616
Comma or space separated subset of agents to build (default: all)
17-
Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, junie, codex, kilocode, auggie, roo, codebuddy, amp, kiro-cli, bob, qodercli, shai, tabnine, agy, vibe, kimi, trae, pi, iflow, generic
17+
Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, junie, codex, kilocode, auggie, roo, codebuddy, amp, kiro-cli, bob, qodercli, shai, tabnine, agy, vibe, kimi, trae, pi, iflow, forge, generic
1818
1919
.PARAMETER Scripts
2020
Comma or space separated subset of script types to build (default: both)
@@ -73,7 +73,8 @@ function Generate-Commands {
7373
[string]$Extension,
7474
[string]$ArgFormat,
7575
[string]$OutputDir,
76-
[string]$ScriptVariant
76+
[string]$ScriptVariant,
77+
[string]$ExtraStripKey = ""
7778
)
7879

7980
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
@@ -137,7 +138,16 @@ function Generate-Commands {
137138
}
138139

139140
if ($inFrontmatter) {
141+
# Check for scripts/agent_scripts or extra strip key
142+
$shouldSkip = $false
140143
if ($line -match '^(scripts|agent_scripts):$') {
144+
$shouldSkip = $true
145+
}
146+
if (-not [string]::IsNullOrEmpty($ExtraStripKey) -and $line -match "^${ExtraStripKey}:") {
147+
$shouldSkip = $true
148+
}
149+
150+
if ($shouldSkip) {
141151
$skipScripts = $true
142152
continue
143153
}
@@ -156,6 +166,7 @@ function Generate-Commands {
156166

157167
# Apply other substitutions
158168
$body = $body -replace '\{ARGS\}', $ArgFormat
169+
$body = $body -replace '\$ARGUMENTS', $ArgFormat
159170
$body = $body -replace '__AGENT__', $Agent
160171
$body = Rewrite-Paths -Content $body
161172

@@ -477,6 +488,22 @@ function Build-Variant {
477488
$cmdDir = Join-Path $baseDir ".iflow/commands"
478489
Generate-Commands -Agent 'iflow' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script
479490
}
491+
'forge' {
492+
$cmdDir = Join-Path $baseDir ".forge/commands"
493+
Generate-Commands -Agent 'forge' -Extension 'md' -ArgFormat '{{parameters}}' -OutputDir $cmdDir -ScriptVariant $Script -ExtraStripKey 'handoffs'
494+
495+
# Inject name field into frontmatter (forge requires name + description)
496+
$cmdFiles = Get-ChildItem -Path "$cmdDir/*.md" -File -ErrorAction SilentlyContinue
497+
foreach ($cmdFile in $cmdFiles) {
498+
$cmdName = [System.IO.Path]::GetFileNameWithoutExtension($cmdFile.Name)
499+
$content = Get-Content -Path $cmdFile.FullName -Raw
500+
501+
# Inject name field after first ---
502+
$content = $content -replace '(?m)^---$', "---`nname: $cmdName", 1
503+
504+
Set-Content -Path $cmdFile.FullName -Value $content -NoNewline
505+
}
506+
}
480507
'generic' {
481508
$cmdDir = Join-Path $baseDir ".speckit/commands"
482509
Generate-Commands -Agent 'generic' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script
@@ -493,7 +520,7 @@ function Build-Variant {
493520
}
494521

495522
# Define all agents and scripts
496-
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'junie', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'tabnine', 'agy', 'vibe', 'kimi', 'trae', 'pi', 'iflow', 'generic')
523+
$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'junie', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'tabnine', 'agy', 'vibe', 'kimi', 'trae', 'pi', 'iflow', 'forge', 'generic')
497524
$AllScripts = @('sh', 'ps')
498525

499526
function Normalize-List {

tests/test_core_pack_scaffold.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,12 +466,12 @@ def test_markdown_has_frontmatter(agent, scaffolded_sh):
466466

467467
def test_forge_name_field_in_frontmatter(scaffolded_sh):
468468
"""Forge: every command file must have a 'name' field in frontmatter that matches the filename.
469-
469+
470470
Forge requires both 'name' and 'description' fields in command frontmatter.
471471
This test ensures the release script's name injection is working correctly.
472472
"""
473473
project = scaffolded_sh("forge")
474-
474+
475475
cmd_dir = _expected_cmd_dir(project, "forge")
476476
for f in _list_command_files(cmd_dir, "forge"):
477477
content = f.read_text(encoding="utf-8")
@@ -482,13 +482,13 @@ def test_forge_name_field_in_frontmatter(scaffolded_sh):
482482
assert len(parts) >= 3, f"Incomplete frontmatter in '{f.name}'"
483483
fm = yaml.safe_load(parts[1])
484484
assert fm is not None, f"Empty frontmatter in '{f.name}'"
485-
485+
486486
# Check that 'name' field exists
487487
assert "name" in fm, (
488488
f"'name' key missing from frontmatter in '{f.name}' - "
489489
f"Forge requires both 'name' and 'description' fields"
490490
)
491-
491+
492492
# Check that name matches the filename (without extension)
493493
expected_name = f.name.removesuffix(".md")
494494
actual_name = fm["name"]

0 commit comments

Comments
 (0)