specops-cli 0.0.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- specops_cli-0.0.22/.github/workflows/release.yml +59 -0
- specops_cli-0.0.22/.github/workflows/scripts/check-release-exists.sh +21 -0
- specops_cli-0.0.22/.github/workflows/scripts/create-github-release.sh +54 -0
- specops_cli-0.0.22/.github/workflows/scripts/create-release-packages.sh +282 -0
- specops_cli-0.0.22/.github/workflows/scripts/generate-release-notes.sh +40 -0
- specops_cli-0.0.22/.github/workflows/scripts/get-next-version.sh +24 -0
- specops_cli-0.0.22/.gitignore +46 -0
- specops_cli-0.0.22/AGENTS.md +430 -0
- specops_cli-0.0.22/PKG-INFO +11 -0
- specops_cli-0.0.22/README.md +372 -0
- specops_cli-0.0.22/STRUCTURE.md +98 -0
- specops_cli-0.0.22/memory/constitution.md +459 -0
- specops_cli-0.0.22/pyproject.toml +23 -0
- specops_cli-0.0.22/scripts/bash/check-prerequisites.sh +166 -0
- specops_cli-0.0.22/scripts/bash/common.sh +155 -0
- specops_cli-0.0.22/scripts/bash/create-new-feature.sh +297 -0
- specops_cli-0.0.22/scripts/bash/setup-plan.sh +60 -0
- specops_cli-0.0.22/scripts/bash/update-agent-context.sh +798 -0
- specops_cli-0.0.22/spec-driven.md +412 -0
- specops_cli-0.0.22/src/specops_cli/__init__.py +1363 -0
- specops_cli-0.0.22/templates/agent-file-template.md +30 -0
- specops_cli-0.0.22/templates/checklist-template.md +40 -0
- specops_cli-0.0.22/templates/commands/analyze.md +187 -0
- specops_cli-0.0.22/templates/commands/checklist.md +297 -0
- specops_cli-0.0.22/templates/commands/clarify.md +697 -0
- specops_cli-0.0.22/templates/commands/constitution.md +307 -0
- specops_cli-0.0.22/templates/commands/deploy.md +127 -0
- specops_cli-0.0.22/templates/commands/implement.md +148 -0
- specops_cli-0.0.22/templates/commands/plan.md +102 -0
- specops_cli-0.0.22/templates/commands/specify.md +266 -0
- specops_cli-0.0.22/templates/commands/tasks.md +140 -0
- specops_cli-0.0.22/templates/commands/taskstoissues.md +33 -0
- specops_cli-0.0.22/templates/plan-template.md +141 -0
- specops_cli-0.0.22/templates/spec-template.md +124 -0
- specops_cli-0.0.22/templates/tasks-template.md +267 -0
- specops_cli-0.0.22/templates/vscode-settings.json +13 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Create Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
paths:
|
|
7
|
+
- 'memory/**'
|
|
8
|
+
- 'scripts/**'
|
|
9
|
+
- 'templates/**'
|
|
10
|
+
- '.github/workflows/**'
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
pull-requests: write
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
- name: Get latest tag
|
|
26
|
+
id: get_tag
|
|
27
|
+
run: |
|
|
28
|
+
chmod +x .github/workflows/scripts/get-next-version.sh
|
|
29
|
+
.github/workflows/scripts/get-next-version.sh
|
|
30
|
+
- name: Check if release already exists
|
|
31
|
+
id: check_release
|
|
32
|
+
run: |
|
|
33
|
+
chmod +x .github/workflows/scripts/check-release-exists.sh
|
|
34
|
+
.github/workflows/scripts/check-release-exists.sh ${{ steps.get_tag.outputs.new_version }}
|
|
35
|
+
env:
|
|
36
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
- name: Create release package variants
|
|
38
|
+
if: steps.check_release.outputs.exists == 'false'
|
|
39
|
+
run: |
|
|
40
|
+
chmod +x .github/workflows/scripts/create-release-packages.sh
|
|
41
|
+
.github/workflows/scripts/create-release-packages.sh ${{ steps.get_tag.outputs.new_version }}
|
|
42
|
+
- name: Generate release notes
|
|
43
|
+
if: steps.check_release.outputs.exists == 'false'
|
|
44
|
+
id: release_notes
|
|
45
|
+
run: |
|
|
46
|
+
chmod +x .github/workflows/scripts/generate-release-notes.sh
|
|
47
|
+
.github/workflows/scripts/generate-release-notes.sh ${{ steps.get_tag.outputs.new_version }} ${{ steps.get_tag.outputs.latest_tag }}
|
|
48
|
+
- name: Create GitHub Release
|
|
49
|
+
if: steps.check_release.outputs.exists == 'false'
|
|
50
|
+
run: |
|
|
51
|
+
chmod +x .github/workflows/scripts/create-github-release.sh
|
|
52
|
+
.github/workflows/scripts/create-github-release.sh ${{ steps.get_tag.outputs.new_version }}
|
|
53
|
+
env:
|
|
54
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
55
|
+
- name: Update version in pyproject.toml (for release artifacts only)
|
|
56
|
+
if: steps.check_release.outputs.exists == 'false'
|
|
57
|
+
run: |
|
|
58
|
+
chmod +x .github/workflows/scripts/update-version.sh
|
|
59
|
+
.github/workflows/scripts/update-version.sh ${{ steps.get_tag.outputs.new_version }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# check-release-exists.sh
|
|
5
|
+
# Check if a GitHub release already exists for the given version
|
|
6
|
+
# Usage: check-release-exists.sh <version>
|
|
7
|
+
|
|
8
|
+
if [[ $# -ne 1 ]]; then
|
|
9
|
+
echo "Usage: $0 <version>" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
VERSION="$1"
|
|
14
|
+
|
|
15
|
+
if gh release view "$VERSION" >/dev/null 2>&1; then
|
|
16
|
+
echo "exists=true" >> $GITHUB_OUTPUT
|
|
17
|
+
echo "Release $VERSION already exists, skipping..."
|
|
18
|
+
else
|
|
19
|
+
echo "exists=false" >> $GITHUB_OUTPUT
|
|
20
|
+
echo "Release $VERSION does not exist, proceeding..."
|
|
21
|
+
fi
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# create-github-release.sh
|
|
5
|
+
# Create a GitHub release with all template zip files
|
|
6
|
+
# Usage: create-github-release.sh <version>
|
|
7
|
+
|
|
8
|
+
if [[ $# -ne 1 ]]; then
|
|
9
|
+
echo "Usage: $0 <version>" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
VERSION="$1"
|
|
14
|
+
|
|
15
|
+
# Remove 'v' prefix from version for release title
|
|
16
|
+
VERSION_NO_V=${VERSION#v}
|
|
17
|
+
|
|
18
|
+
gh release create "$VERSION" \
|
|
19
|
+
.genreleases/spec-ops-template-copilot-sh-"$VERSION".zip \
|
|
20
|
+
.genreleases/spec-ops-template-copilot-ps-"$VERSION".zip \
|
|
21
|
+
.genreleases/spec-ops-template-claude-sh-"$VERSION".zip \
|
|
22
|
+
.genreleases/spec-ops-template-claude-ps-"$VERSION".zip \
|
|
23
|
+
.genreleases/spec-ops-template-gemini-sh-"$VERSION".zip \
|
|
24
|
+
.genreleases/spec-ops-template-gemini-ps-"$VERSION".zip \
|
|
25
|
+
.genreleases/spec-ops-template-cursor-agent-sh-"$VERSION".zip \
|
|
26
|
+
.genreleases/spec-ops-template-cursor-agent-ps-"$VERSION".zip \
|
|
27
|
+
.genreleases/spec-ops-template-opencode-sh-"$VERSION".zip \
|
|
28
|
+
.genreleases/spec-ops-template-opencode-ps-"$VERSION".zip \
|
|
29
|
+
.genreleases/spec-ops-template-qwen-sh-"$VERSION".zip \
|
|
30
|
+
.genreleases/spec-ops-template-qwen-ps-"$VERSION".zip \
|
|
31
|
+
.genreleases/spec-ops-template-windsurf-sh-"$VERSION".zip \
|
|
32
|
+
.genreleases/spec-ops-template-windsurf-ps-"$VERSION".zip \
|
|
33
|
+
.genreleases/spec-ops-template-codex-sh-"$VERSION".zip \
|
|
34
|
+
.genreleases/spec-ops-template-codex-ps-"$VERSION".zip \
|
|
35
|
+
.genreleases/spec-ops-template-kilocode-sh-"$VERSION".zip \
|
|
36
|
+
.genreleases/spec-ops-template-kilocode-ps-"$VERSION".zip \
|
|
37
|
+
.genreleases/spec-ops-template-auggie-sh-"$VERSION".zip \
|
|
38
|
+
.genreleases/spec-ops-template-auggie-ps-"$VERSION".zip \
|
|
39
|
+
.genreleases/spec-ops-template-roo-sh-"$VERSION".zip \
|
|
40
|
+
.genreleases/spec-ops-template-roo-ps-"$VERSION".zip \
|
|
41
|
+
.genreleases/spec-ops-template-codebuddy-sh-"$VERSION".zip \
|
|
42
|
+
.genreleases/spec-ops-template-codebuddy-ps-"$VERSION".zip \
|
|
43
|
+
.genreleases/spec-ops-template-qoder-sh-"$VERSION".zip \
|
|
44
|
+
.genreleases/spec-ops-template-qoder-ps-"$VERSION".zip \
|
|
45
|
+
.genreleases/spec-ops-template-amp-sh-"$VERSION".zip \
|
|
46
|
+
.genreleases/spec-ops-template-amp-ps-"$VERSION".zip \
|
|
47
|
+
.genreleases/spec-ops-template-shai-sh-"$VERSION".zip \
|
|
48
|
+
.genreleases/spec-ops-template-shai-ps-"$VERSION".zip \
|
|
49
|
+
.genreleases/spec-ops-template-q-sh-"$VERSION".zip \
|
|
50
|
+
.genreleases/spec-ops-template-q-ps-"$VERSION".zip \
|
|
51
|
+
.genreleases/spec-ops-template-bob-sh-"$VERSION".zip \
|
|
52
|
+
.genreleases/spec-ops-template-bob-ps-"$VERSION".zip \
|
|
53
|
+
--title "Spec Ops Templates - $VERSION_NO_V" \
|
|
54
|
+
--notes-file release_notes.md
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# create-release-packages.sh (workflow-local)
|
|
5
|
+
# Build Spec Ops template release archives for each supported AI assistant and script type.
|
|
6
|
+
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
|
|
7
|
+
# Version argument should include leading 'v'.
|
|
8
|
+
# Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built.
|
|
9
|
+
# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai bob (default: all)
|
|
10
|
+
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
|
|
11
|
+
# Examples:
|
|
12
|
+
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
|
|
13
|
+
# AGENTS="copilot,gemini" $0 v0.2.0
|
|
14
|
+
# SCRIPTS=ps $0 v0.2.0
|
|
15
|
+
|
|
16
|
+
if [[ $# -ne 1 ]]; then
|
|
17
|
+
echo "Usage: $0 <version-with-v-prefix>" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
NEW_VERSION="$1"
|
|
21
|
+
if [[ ! $NEW_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
22
|
+
echo "Version must look like v0.0.0" >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
echo "Building release packages for $NEW_VERSION"
|
|
27
|
+
|
|
28
|
+
# Create and use .genreleases directory for all build artifacts
|
|
29
|
+
GENRELEASES_DIR=".genreleases"
|
|
30
|
+
mkdir -p "$GENRELEASES_DIR"
|
|
31
|
+
rm -rf "$GENRELEASES_DIR"/* || true
|
|
32
|
+
|
|
33
|
+
rewrite_paths() {
|
|
34
|
+
sed -E \
|
|
35
|
+
-e 's@(/?)memory/@.specops/memory/@g' \
|
|
36
|
+
-e 's@(/?)scripts/@.specops/scripts/@g' \
|
|
37
|
+
-e 's@(/?)templates/@.specops/templates/@g'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
generate_commands() {
|
|
41
|
+
local agent=$1 ext=$2 arg_format=$3 output_dir=$4 script_variant=$5
|
|
42
|
+
mkdir -p "$output_dir"
|
|
43
|
+
for template in templates/commands/*.md; do
|
|
44
|
+
[[ -f "$template" ]] || continue
|
|
45
|
+
local name description script_command agent_script_command body
|
|
46
|
+
name=$(basename "$template" .md)
|
|
47
|
+
|
|
48
|
+
# Normalize line endings
|
|
49
|
+
file_content=$(tr -d '\r' < "$template")
|
|
50
|
+
|
|
51
|
+
# Extract description and script command from YAML frontmatter
|
|
52
|
+
description=$(printf '%s\n' "$file_content" | awk '/^description:/ {sub(/^description:[[:space:]]*/, ""); print; exit}')
|
|
53
|
+
script_command=$(printf '%s\n' "$file_content" | awk -v sv="$script_variant" '/^[[:space:]]*'"$script_variant"':[[:space:]]*/ {sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, ""); print; exit}')
|
|
54
|
+
|
|
55
|
+
if [[ -z $script_command ]]; then
|
|
56
|
+
echo "Warning: no script command found for $script_variant in $template" >&2
|
|
57
|
+
script_command="(Missing script command for $script_variant)"
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Extract agent_script command from YAML frontmatter if present
|
|
61
|
+
agent_script_command=$(printf '%s\n' "$file_content" | awk '
|
|
62
|
+
/^agent_scripts:$/ { in_agent_scripts=1; next }
|
|
63
|
+
in_agent_scripts && /^[[:space:]]*'"$script_variant"':[[:space:]]*/ {
|
|
64
|
+
sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, "")
|
|
65
|
+
print
|
|
66
|
+
exit
|
|
67
|
+
}
|
|
68
|
+
in_agent_scripts && /^[a-zA-Z]/ { in_agent_scripts=0 }
|
|
69
|
+
')
|
|
70
|
+
|
|
71
|
+
# Replace {SCRIPT} placeholder with the script command
|
|
72
|
+
body=$(printf '%s\n' "$file_content" | sed "s|{SCRIPT}|${script_command}|g")
|
|
73
|
+
|
|
74
|
+
# Replace {AGENT_SCRIPT} placeholder with the agent script command if found
|
|
75
|
+
if [[ -n $agent_script_command ]]; then
|
|
76
|
+
body=$(printf '%s\n' "$body" | sed "s|{AGENT_SCRIPT}|${agent_script_command}|g")
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Remove the scripts: and agent_scripts: sections from frontmatter while preserving YAML structure
|
|
80
|
+
body=$(printf '%s\n' "$body" | awk '
|
|
81
|
+
/^---$/ { print; if (++dash_count == 1) in_frontmatter=1; else in_frontmatter=0; next }
|
|
82
|
+
in_frontmatter && /^scripts:$/ { skip_scripts=1; next }
|
|
83
|
+
in_frontmatter && /^agent_scripts:$/ { skip_scripts=1; next }
|
|
84
|
+
in_frontmatter && /^[a-zA-Z].*:/ && skip_scripts { skip_scripts=0 }
|
|
85
|
+
in_frontmatter && skip_scripts && /^[[:space:]]/ { next }
|
|
86
|
+
{ print }
|
|
87
|
+
')
|
|
88
|
+
|
|
89
|
+
# Apply other substitutions
|
|
90
|
+
body=$(printf '%s\n' "$body" | sed "s/{ARGS}/$arg_format/g" | sed "s/__AGENT__/$agent/g" | rewrite_paths)
|
|
91
|
+
|
|
92
|
+
case $ext in
|
|
93
|
+
toml)
|
|
94
|
+
body=$(printf '%s\n' "$body" | sed 's/\\/\\\\/g')
|
|
95
|
+
{ echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/specops.$name.$ext" ;;
|
|
96
|
+
md)
|
|
97
|
+
echo "$body" > "$output_dir/specops.$name.$ext" ;;
|
|
98
|
+
agent.md)
|
|
99
|
+
echo "$body" > "$output_dir/specops.$name.$ext" ;;
|
|
100
|
+
esac
|
|
101
|
+
done
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
generate_copilot_prompts() {
|
|
105
|
+
local agents_dir=$1 prompts_dir=$2
|
|
106
|
+
mkdir -p "$prompts_dir"
|
|
107
|
+
|
|
108
|
+
# Generate a .prompt.md file for each .agent.md file
|
|
109
|
+
for agent_file in "$agents_dir"/specops.*.agent.md; do
|
|
110
|
+
[[ -f "$agent_file" ]] || continue
|
|
111
|
+
|
|
112
|
+
local basename=$(basename "$agent_file" .agent.md)
|
|
113
|
+
local prompt_file="$prompts_dir/${basename}.prompt.md"
|
|
114
|
+
|
|
115
|
+
# Create prompt file with agent frontmatter
|
|
116
|
+
cat > "$prompt_file" <<EOF
|
|
117
|
+
---
|
|
118
|
+
agent: ${basename}
|
|
119
|
+
---
|
|
120
|
+
EOF
|
|
121
|
+
done
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
build_variant() {
|
|
125
|
+
local agent=$1 script=$2
|
|
126
|
+
local base_dir="$GENRELEASES_DIR/sdd-${agent}-package-${script}"
|
|
127
|
+
echo "Building $agent ($script) package..."
|
|
128
|
+
mkdir -p "$base_dir"
|
|
129
|
+
|
|
130
|
+
# Copy base structure but filter scripts by variant
|
|
131
|
+
SPEC_DIR="$base_dir/.specops"
|
|
132
|
+
mkdir -p "$SPEC_DIR"
|
|
133
|
+
|
|
134
|
+
[[ -d memory ]] && { cp -r memory "$SPEC_DIR/"; echo "Copied memory -> .specops"; }
|
|
135
|
+
|
|
136
|
+
# Only copy the relevant script variant directory
|
|
137
|
+
if [[ -d scripts ]]; then
|
|
138
|
+
mkdir -p "$SPEC_DIR/scripts"
|
|
139
|
+
case $script in
|
|
140
|
+
sh)
|
|
141
|
+
[[ -d scripts/bash ]] && { cp -r scripts/bash "$SPEC_DIR/scripts/"; echo "Copied scripts/bash -> .specops/scripts"; }
|
|
142
|
+
# Copy any script files that aren't in variant-specific directories
|
|
143
|
+
find scripts -maxdepth 1 -type f -exec cp {} "$SPEC_DIR/scripts/" \; 2>/dev/null || true
|
|
144
|
+
;;
|
|
145
|
+
ps)
|
|
146
|
+
[[ -d scripts/powershell ]] && { cp -r scripts/powershell "$SPEC_DIR/scripts/"; echo "Copied scripts/powershell -> .specops/scripts"; }
|
|
147
|
+
# Copy any script files that aren't in variant-specific directories
|
|
148
|
+
find scripts -maxdepth 1 -type f -exec cp {} "$SPEC_DIR/scripts/" \; 2>/dev/null || true
|
|
149
|
+
;;
|
|
150
|
+
esac
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# Copy templates (excluding commands/ and vscode-settings.json) - macOS compatible
|
|
154
|
+
if [[ -d templates ]]; then
|
|
155
|
+
mkdir -p "$SPEC_DIR/templates"
|
|
156
|
+
find templates -type f -not -path "templates/commands/*" -not -name "vscode-settings.json" | while read -r file; do
|
|
157
|
+
dest_dir="$SPEC_DIR/$(dirname "$file")"
|
|
158
|
+
mkdir -p "$dest_dir"
|
|
159
|
+
cp "$file" "$dest_dir/"
|
|
160
|
+
done
|
|
161
|
+
echo "Copied templates -> .specops/templates"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# NOTE: We substitute {ARGS} internally. Outward tokens differ intentionally:
|
|
165
|
+
# * Markdown/prompt (claude, copilot, cursor-agent, opencode): $ARGUMENTS
|
|
166
|
+
# * TOML (gemini, qwen): {{args}}
|
|
167
|
+
# This keeps formats readable without extra abstraction.
|
|
168
|
+
|
|
169
|
+
case $agent in
|
|
170
|
+
claude)
|
|
171
|
+
mkdir -p "$base_dir/.claude/commands"
|
|
172
|
+
generate_commands claude md "\$ARGUMENTS" "$base_dir/.claude/commands" "$script" ;;
|
|
173
|
+
gemini)
|
|
174
|
+
mkdir -p "$base_dir/.gemini/commands"
|
|
175
|
+
generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script"
|
|
176
|
+
[[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;;
|
|
177
|
+
copilot)
|
|
178
|
+
mkdir -p "$base_dir/.github/agents"
|
|
179
|
+
generate_commands copilot agent.md "\$ARGUMENTS" "$base_dir/.github/agents" "$script"
|
|
180
|
+
# Generate companion prompt files
|
|
181
|
+
generate_copilot_prompts "$base_dir/.github/agents" "$base_dir/.github/prompts"
|
|
182
|
+
# Create VS Code workspace settings
|
|
183
|
+
mkdir -p "$base_dir/.vscode"
|
|
184
|
+
[[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json"
|
|
185
|
+
;;
|
|
186
|
+
cursor-agent)
|
|
187
|
+
mkdir -p "$base_dir/.cursor/commands"
|
|
188
|
+
generate_commands cursor-agent md "\$ARGUMENTS" "$base_dir/.cursor/commands" "$script" ;;
|
|
189
|
+
qwen)
|
|
190
|
+
mkdir -p "$base_dir/.qwen/commands"
|
|
191
|
+
generate_commands qwen toml "{{args}}" "$base_dir/.qwen/commands" "$script"
|
|
192
|
+
[[ -f agent_templates/qwen/QWEN.md ]] && cp agent_templates/qwen/QWEN.md "$base_dir/QWEN.md" ;;
|
|
193
|
+
opencode)
|
|
194
|
+
mkdir -p "$base_dir/.opencode/command"
|
|
195
|
+
generate_commands opencode md "\$ARGUMENTS" "$base_dir/.opencode/command" "$script" ;;
|
|
196
|
+
windsurf)
|
|
197
|
+
mkdir -p "$base_dir/.windsurf/workflows"
|
|
198
|
+
generate_commands windsurf md "\$ARGUMENTS" "$base_dir/.windsurf/workflows" "$script" ;;
|
|
199
|
+
codex)
|
|
200
|
+
mkdir -p "$base_dir/.codex/prompts"
|
|
201
|
+
generate_commands codex md "\$ARGUMENTS" "$base_dir/.codex/prompts" "$script" ;;
|
|
202
|
+
kilocode)
|
|
203
|
+
mkdir -p "$base_dir/.kilocode/workflows"
|
|
204
|
+
generate_commands kilocode md "\$ARGUMENTS" "$base_dir/.kilocode/workflows" "$script" ;;
|
|
205
|
+
auggie)
|
|
206
|
+
mkdir -p "$base_dir/.augment/commands"
|
|
207
|
+
generate_commands auggie md "\$ARGUMENTS" "$base_dir/.augment/commands" "$script" ;;
|
|
208
|
+
roo)
|
|
209
|
+
mkdir -p "$base_dir/.roo/commands"
|
|
210
|
+
generate_commands roo md "\$ARGUMENTS" "$base_dir/.roo/commands" "$script" ;;
|
|
211
|
+
codebuddy)
|
|
212
|
+
mkdir -p "$base_dir/.codebuddy/commands"
|
|
213
|
+
generate_commands codebuddy md "\$ARGUMENTS" "$base_dir/.codebuddy/commands" "$script" ;;
|
|
214
|
+
qoder)
|
|
215
|
+
mkdir -p "$base_dir/.qoder/commands"
|
|
216
|
+
generate_commands qoder md "\$ARGUMENTS" "$base_dir/.qoder/commands" "$script" ;;
|
|
217
|
+
amp)
|
|
218
|
+
mkdir -p "$base_dir/.agents/commands"
|
|
219
|
+
generate_commands amp md "\$ARGUMENTS" "$base_dir/.agents/commands" "$script" ;;
|
|
220
|
+
shai)
|
|
221
|
+
mkdir -p "$base_dir/.shai/commands"
|
|
222
|
+
generate_commands shai md "\$ARGUMENTS" "$base_dir/.shai/commands" "$script" ;;
|
|
223
|
+
q)
|
|
224
|
+
mkdir -p "$base_dir/.amazonq/prompts"
|
|
225
|
+
generate_commands q md "\$ARGUMENTS" "$base_dir/.amazonq/prompts" "$script" ;;
|
|
226
|
+
bob)
|
|
227
|
+
mkdir -p "$base_dir/.bob/commands"
|
|
228
|
+
generate_commands bob md "\$ARGUMENTS" "$base_dir/.bob/commands" "$script" ;;
|
|
229
|
+
esac
|
|
230
|
+
( cd "$base_dir" && zip -r "../spec-ops-template-${agent}-${script}-${NEW_VERSION}.zip" . )
|
|
231
|
+
echo "Created $GENRELEASES_DIR/spec-ops-template-${agent}-${script}-${NEW_VERSION}.zip"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# Determine agent list
|
|
235
|
+
#ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q bob qoder)
|
|
236
|
+
ALL_AGENTS=(claude copilot)
|
|
237
|
+
ALL_SCRIPTS=(sh ps)
|
|
238
|
+
|
|
239
|
+
norm_list() {
|
|
240
|
+
# convert comma+space separated -> line separated unique while preserving order of first occurrence
|
|
241
|
+
tr ',\n' ' ' | awk '{for(i=1;i<=NF;i++){if(!seen[$i]++){printf((out?"\n":"") $i);out=1}}}END{printf("\n")}'
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
validate_subset() {
|
|
245
|
+
local type=$1; shift; local -n allowed=$1; shift; local items=("$@")
|
|
246
|
+
local invalid=0
|
|
247
|
+
for it in "${items[@]}"; do
|
|
248
|
+
local found=0
|
|
249
|
+
for a in "${allowed[@]}"; do [[ $it == "$a" ]] && { found=1; break; }; done
|
|
250
|
+
if [[ $found -eq 0 ]]; then
|
|
251
|
+
echo "Error: unknown $type '$it' (allowed: ${allowed[*]})" >&2
|
|
252
|
+
invalid=1
|
|
253
|
+
fi
|
|
254
|
+
done
|
|
255
|
+
return $invalid
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if [[ -n ${AGENTS:-} ]]; then
|
|
259
|
+
mapfile -t AGENT_LIST < <(printf '%s' "$AGENTS" | norm_list)
|
|
260
|
+
validate_subset agent ALL_AGENTS "${AGENT_LIST[@]}" || exit 1
|
|
261
|
+
else
|
|
262
|
+
AGENT_LIST=("${ALL_AGENTS[@]}")
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
if [[ -n ${SCRIPTS:-} ]]; then
|
|
266
|
+
mapfile -t SCRIPT_LIST < <(printf '%s' "$SCRIPTS" | norm_list)
|
|
267
|
+
validate_subset script ALL_SCRIPTS "${SCRIPT_LIST[@]}" || exit 1
|
|
268
|
+
else
|
|
269
|
+
SCRIPT_LIST=("${ALL_SCRIPTS[@]}")
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
echo "Agents: ${AGENT_LIST[*]}"
|
|
273
|
+
echo "Scripts: ${SCRIPT_LIST[*]}"
|
|
274
|
+
|
|
275
|
+
for agent in "${AGENT_LIST[@]}"; do
|
|
276
|
+
for script in "${SCRIPT_LIST[@]}"; do
|
|
277
|
+
build_variant "$agent" "$script"
|
|
278
|
+
done
|
|
279
|
+
done
|
|
280
|
+
|
|
281
|
+
echo "Archives in $GENRELEASES_DIR:"
|
|
282
|
+
ls -1 "$GENRELEASES_DIR"/spec-ops-template-*-"${NEW_VERSION}".zip
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# generate-release-notes.sh
|
|
5
|
+
# Generate release notes from git history
|
|
6
|
+
# Usage: generate-release-notes.sh <new_version> <last_tag>
|
|
7
|
+
|
|
8
|
+
if [[ $# -ne 2 ]]; then
|
|
9
|
+
echo "Usage: $0 <new_version> <last_tag>" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
NEW_VERSION="$1"
|
|
14
|
+
LAST_TAG="$2"
|
|
15
|
+
|
|
16
|
+
# Get commits since last tag
|
|
17
|
+
if [ "$LAST_TAG" = "v0.0.0" ]; then
|
|
18
|
+
# Check how many commits we have and use that as the limit
|
|
19
|
+
COMMIT_COUNT=$(git rev-list --count HEAD)
|
|
20
|
+
if [ "$COMMIT_COUNT" -gt 10 ]; then
|
|
21
|
+
COMMITS=$(git log --oneline --pretty=format:"- %s" HEAD~10..HEAD)
|
|
22
|
+
else
|
|
23
|
+
COMMITS=$(git log --oneline --pretty=format:"- %s" HEAD~$COMMIT_COUNT..HEAD 2>/dev/null || git log --oneline --pretty=format:"- %s")
|
|
24
|
+
fi
|
|
25
|
+
else
|
|
26
|
+
COMMITS=$(git log --oneline --pretty=format:"- %s" $LAST_TAG..HEAD)
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Create release notes
|
|
30
|
+
cat > release_notes.md << EOF
|
|
31
|
+
This is the latest set of releases that you can use with your agent of choice. We recommend using the Specify CLI to scaffold your projects, however you can download these independently and manage them yourself.
|
|
32
|
+
|
|
33
|
+
## Changelog
|
|
34
|
+
|
|
35
|
+
$COMMITS
|
|
36
|
+
|
|
37
|
+
EOF
|
|
38
|
+
|
|
39
|
+
echo "Generated release notes:"
|
|
40
|
+
cat release_notes.md
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# get-next-version.sh
|
|
5
|
+
# Calculate the next version based on the latest git tag and output GitHub Actions variables
|
|
6
|
+
# Usage: get-next-version.sh
|
|
7
|
+
|
|
8
|
+
# Get the latest tag, or use v0.0.0 if no tags exist
|
|
9
|
+
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
|
|
10
|
+
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
|
|
11
|
+
|
|
12
|
+
# Extract version number and increment
|
|
13
|
+
VERSION=$(echo $LATEST_TAG | sed 's/v//')
|
|
14
|
+
IFS='.' read -ra VERSION_PARTS <<< "$VERSION"
|
|
15
|
+
MAJOR=${VERSION_PARTS[0]:-0}
|
|
16
|
+
MINOR=${VERSION_PARTS[1]:-0}
|
|
17
|
+
PATCH=${VERSION_PARTS[2]:-0}
|
|
18
|
+
|
|
19
|
+
# Increment patch version
|
|
20
|
+
PATCH=$((PATCH + 1))
|
|
21
|
+
NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
|
|
22
|
+
|
|
23
|
+
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
24
|
+
echo "New version will be: $NEW_VERSION"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
.venv
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
.DS_Store
|
|
35
|
+
*.tmp
|
|
36
|
+
|
|
37
|
+
# Project specific
|
|
38
|
+
*.log
|
|
39
|
+
.env
|
|
40
|
+
.env.local
|
|
41
|
+
*.lock
|
|
42
|
+
|
|
43
|
+
# Spec Kit-specific files
|
|
44
|
+
.genreleases/
|
|
45
|
+
*.zip
|
|
46
|
+
sdd-*/
|