cocoaskills 0.2.0__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.
- cocoaskills-0.2.0/.github/workflows/ci.yml +90 -0
- cocoaskills-0.2.0/.github/workflows/distribution-smoke.yml +399 -0
- cocoaskills-0.2.0/.github/workflows/release.yml +118 -0
- cocoaskills-0.2.0/.gitignore +38 -0
- cocoaskills-0.2.0/CHANGELOG.md +81 -0
- cocoaskills-0.2.0/LICENSE +201 -0
- cocoaskills-0.2.0/PKG-INFO +202 -0
- cocoaskills-0.2.0/README.md +168 -0
- cocoaskills-0.2.0/docs/CNAME +1 -0
- cocoaskills-0.2.0/docs/index.html +53 -0
- cocoaskills-0.2.0/docs/install.sh +64 -0
- cocoaskills-0.2.0/docs/mvp-design.md +1008 -0
- cocoaskills-0.2.0/pyproject.toml +70 -0
- cocoaskills-0.2.0/setup.cfg +4 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/PKG-INFO +202 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/SOURCES.txt +65 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/dependency_links.txt +1 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/entry_points.txt +2 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/requires.txt +5 -0
- cocoaskills-0.2.0/src/cocoaskills.egg-info/top_level.txt +1 -0
- cocoaskills-0.2.0/src/csk/__init__.py +18 -0
- cocoaskills-0.2.0/src/csk/__main__.py +6 -0
- cocoaskills-0.2.0/src/csk/_version.py +24 -0
- cocoaskills-0.2.0/src/csk/adapters.py +120 -0
- cocoaskills-0.2.0/src/csk/cli.py +452 -0
- cocoaskills-0.2.0/src/csk/config.py +197 -0
- cocoaskills-0.2.0/src/csk/env_files.py +26 -0
- cocoaskills-0.2.0/src/csk/gc.py +35 -0
- cocoaskills-0.2.0/src/csk/git_ops.py +111 -0
- cocoaskills-0.2.0/src/csk/gitignore_gate.py +49 -0
- cocoaskills-0.2.0/src/csk/hashing.py +26 -0
- cocoaskills-0.2.0/src/csk/installer.py +314 -0
- cocoaskills-0.2.0/src/csk/locale.py +105 -0
- cocoaskills-0.2.0/src/csk/locking.py +64 -0
- cocoaskills-0.2.0/src/csk/manifest.py +140 -0
- cocoaskills-0.2.0/src/csk/project_resolver.py +108 -0
- cocoaskills-0.2.0/src/csk/shell_init.py +77 -0
- cocoaskills-0.2.0/src/csk/shims.py +77 -0
- cocoaskills-0.2.0/src/csk/skillspec.py +126 -0
- cocoaskills-0.2.0/src/csk/snapshot.py +32 -0
- cocoaskills-0.2.0/src/csk/status.py +84 -0
- cocoaskills-0.2.0/src/csk/whitelist.py +98 -0
- cocoaskills-0.2.0/tests/conftest.py +114 -0
- cocoaskills-0.2.0/tests/fixtures/skill_legacy_runtime/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/fixtures/skill_minimal/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/fixtures/skill_no_remote/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/fixtures/skill_with_locales/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/fixtures/skill_with_scripts/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/fixtures/skill_with_submodule/.gitkeep +1 -0
- cocoaskills-0.2.0/tests/test_adapters.py +62 -0
- cocoaskills-0.2.0/tests/test_cli.py +357 -0
- cocoaskills-0.2.0/tests/test_config.py +64 -0
- cocoaskills-0.2.0/tests/test_e2e.py +120 -0
- cocoaskills-0.2.0/tests/test_env_files.py +11 -0
- cocoaskills-0.2.0/tests/test_gc.py +55 -0
- cocoaskills-0.2.0/tests/test_gitignore_gate.py +21 -0
- cocoaskills-0.2.0/tests/test_hashing.py +16 -0
- cocoaskills-0.2.0/tests/test_install.py +307 -0
- cocoaskills-0.2.0/tests/test_locale.py +51 -0
- cocoaskills-0.2.0/tests/test_locking.py +14 -0
- cocoaskills-0.2.0/tests/test_manifest.py +44 -0
- cocoaskills-0.2.0/tests/test_project_resolver.py +59 -0
- cocoaskills-0.2.0/tests/test_refs.py +23 -0
- cocoaskills-0.2.0/tests/test_shims.py +40 -0
- cocoaskills-0.2.0/tests/test_skillspec.py +50 -0
- cocoaskills-0.2.0/tests/test_status.py +39 -0
- cocoaskills-0.2.0/tests/test_whitelist.py +39 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Tests / Python ${{ matrix.python-version }} on ${{ matrix.os }}
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
21
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
22
|
+
steps:
|
|
23
|
+
- name: Checkout
|
|
24
|
+
uses: actions/checkout@v4
|
|
25
|
+
with:
|
|
26
|
+
fetch-depth: 0
|
|
27
|
+
|
|
28
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
29
|
+
uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
allow-prereleases: true
|
|
33
|
+
|
|
34
|
+
- name: Configure git (POSIX)
|
|
35
|
+
if: runner.os != 'Windows'
|
|
36
|
+
run: |
|
|
37
|
+
git config --global user.email "ci@example.com"
|
|
38
|
+
git config --global user.name "CI"
|
|
39
|
+
git config --global init.defaultBranch main
|
|
40
|
+
|
|
41
|
+
- name: Configure git (Windows)
|
|
42
|
+
if: runner.os == 'Windows'
|
|
43
|
+
shell: pwsh
|
|
44
|
+
run: |
|
|
45
|
+
git config --global user.email "ci@example.com"
|
|
46
|
+
git config --global user.name "CI"
|
|
47
|
+
git config --global init.defaultBranch main
|
|
48
|
+
git config --global core.autocrlf false
|
|
49
|
+
git config --global core.symlinks false
|
|
50
|
+
|
|
51
|
+
- name: Install package
|
|
52
|
+
run: |
|
|
53
|
+
python -m pip install --upgrade pip
|
|
54
|
+
python -m pip install -e ".[dev]"
|
|
55
|
+
|
|
56
|
+
- name: Run tests
|
|
57
|
+
run: python -m pytest -v
|
|
58
|
+
|
|
59
|
+
build:
|
|
60
|
+
name: Build artifacts
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
needs: test
|
|
63
|
+
steps:
|
|
64
|
+
- name: Checkout
|
|
65
|
+
uses: actions/checkout@v4
|
|
66
|
+
with:
|
|
67
|
+
fetch-depth: 0
|
|
68
|
+
|
|
69
|
+
- name: Set up Python
|
|
70
|
+
uses: actions/setup-python@v5
|
|
71
|
+
with:
|
|
72
|
+
python-version: "3.12"
|
|
73
|
+
|
|
74
|
+
- name: Install build tools
|
|
75
|
+
run: |
|
|
76
|
+
python -m pip install --upgrade pip
|
|
77
|
+
python -m pip install build twine
|
|
78
|
+
|
|
79
|
+
- name: Build sdist and wheel
|
|
80
|
+
run: python -m build
|
|
81
|
+
|
|
82
|
+
- name: Verify metadata
|
|
83
|
+
run: twine check dist/*
|
|
84
|
+
|
|
85
|
+
- name: Upload artifacts
|
|
86
|
+
uses: actions/upload-artifact@v4
|
|
87
|
+
with:
|
|
88
|
+
name: dist
|
|
89
|
+
path: dist/
|
|
90
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
name: Distribution Smoke
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_run:
|
|
7
|
+
workflows: ["Release"]
|
|
8
|
+
types: [completed]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
version:
|
|
12
|
+
description: "Version or tag to smoke, for example 0.1.1 or v0.1.1"
|
|
13
|
+
required: true
|
|
14
|
+
type: string
|
|
15
|
+
include_homebrew:
|
|
16
|
+
description: "Also test the Homebrew tap. Enable after the tap formula is bumped."
|
|
17
|
+
required: false
|
|
18
|
+
default: false
|
|
19
|
+
type: boolean
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
resolve-version:
|
|
26
|
+
name: Resolve version
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
if: ${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && !contains(github.event.workflow_run.head_branch, '-')) }}
|
|
29
|
+
outputs:
|
|
30
|
+
version: ${{ steps.version.outputs.version }}
|
|
31
|
+
tag: ${{ steps.version.outputs.tag }}
|
|
32
|
+
steps:
|
|
33
|
+
- name: Normalize version
|
|
34
|
+
id: version
|
|
35
|
+
env:
|
|
36
|
+
RAW_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.event.release.tag_name }}
|
|
37
|
+
run: |
|
|
38
|
+
python - <<'PY' >> "$GITHUB_OUTPUT"
|
|
39
|
+
import os
|
|
40
|
+
|
|
41
|
+
raw = os.environ["RAW_VERSION"].strip()
|
|
42
|
+
tag = raw if raw.startswith("v") else f"v{raw}"
|
|
43
|
+
version = raw[1:] if raw.startswith("v") else raw
|
|
44
|
+
version = version.replace("-rc", "rc").replace("-alpha", "a").replace("-beta", "b")
|
|
45
|
+
print(f"tag={tag}")
|
|
46
|
+
print(f"version={version}")
|
|
47
|
+
PY
|
|
48
|
+
|
|
49
|
+
smoke:
|
|
50
|
+
name: ${{ matrix.channel }} / ${{ matrix.os }}
|
|
51
|
+
needs: resolve-version
|
|
52
|
+
runs-on: ${{ matrix.os }}
|
|
53
|
+
strategy:
|
|
54
|
+
fail-fast: false
|
|
55
|
+
matrix:
|
|
56
|
+
include:
|
|
57
|
+
- os: ubuntu-latest
|
|
58
|
+
channel: pipx
|
|
59
|
+
- os: macos-latest
|
|
60
|
+
channel: pipx
|
|
61
|
+
- os: windows-latest
|
|
62
|
+
channel: pipx
|
|
63
|
+
- os: ubuntu-latest
|
|
64
|
+
channel: uv-tool
|
|
65
|
+
- os: macos-latest
|
|
66
|
+
channel: uv-tool
|
|
67
|
+
- os: windows-latest
|
|
68
|
+
channel: uv-tool
|
|
69
|
+
- os: ubuntu-latest
|
|
70
|
+
channel: mise
|
|
71
|
+
- os: macos-latest
|
|
72
|
+
channel: mise
|
|
73
|
+
- os: ubuntu-latest
|
|
74
|
+
channel: install-sh
|
|
75
|
+
- os: macos-latest
|
|
76
|
+
channel: install-sh
|
|
77
|
+
defaults:
|
|
78
|
+
run:
|
|
79
|
+
shell: bash
|
|
80
|
+
env:
|
|
81
|
+
CSK_VERSION: ${{ needs.resolve-version.outputs.version }}
|
|
82
|
+
steps:
|
|
83
|
+
- name: Set up Python
|
|
84
|
+
uses: actions/setup-python@v5
|
|
85
|
+
with:
|
|
86
|
+
python-version: "3.12"
|
|
87
|
+
|
|
88
|
+
- name: Configure git
|
|
89
|
+
run: |
|
|
90
|
+
git config --global user.email "ci@example.com"
|
|
91
|
+
git config --global user.name "CI"
|
|
92
|
+
git config --global init.defaultBranch main
|
|
93
|
+
git config --global core.autocrlf false
|
|
94
|
+
git config --global core.symlinks false
|
|
95
|
+
|
|
96
|
+
- name: Install with pipx
|
|
97
|
+
if: matrix.channel == 'pipx'
|
|
98
|
+
run: |
|
|
99
|
+
python -m pip install --upgrade pip pipx
|
|
100
|
+
for attempt in 1 2 3 4 5; do
|
|
101
|
+
if python -m pipx install "cocoaskills==$CSK_VERSION"; then
|
|
102
|
+
break
|
|
103
|
+
fi
|
|
104
|
+
python -m pipx uninstall cocoaskills >/dev/null 2>&1 || true
|
|
105
|
+
if [ "$attempt" -eq 5 ]; then
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
sleep $((attempt * 15))
|
|
109
|
+
done
|
|
110
|
+
python - <<'PY' >> "$GITHUB_PATH"
|
|
111
|
+
import subprocess
|
|
112
|
+
import sys
|
|
113
|
+
|
|
114
|
+
print(subprocess.check_output(
|
|
115
|
+
[sys.executable, "-m", "pipx", "environment", "--value", "PIPX_BIN_DIR"],
|
|
116
|
+
text=True,
|
|
117
|
+
).strip())
|
|
118
|
+
PY
|
|
119
|
+
|
|
120
|
+
- name: Install with uv tool
|
|
121
|
+
if: matrix.channel == 'uv-tool'
|
|
122
|
+
run: |
|
|
123
|
+
python -m pip install --upgrade pip uv
|
|
124
|
+
for attempt in 1 2 3 4 5; do
|
|
125
|
+
if python -m uv tool install "cocoaskills==$CSK_VERSION"; then
|
|
126
|
+
break
|
|
127
|
+
fi
|
|
128
|
+
python -m uv tool uninstall cocoaskills >/dev/null 2>&1 || true
|
|
129
|
+
if [ "$attempt" -eq 5 ]; then
|
|
130
|
+
exit 1
|
|
131
|
+
fi
|
|
132
|
+
sleep $((attempt * 15))
|
|
133
|
+
done
|
|
134
|
+
python -m uv tool dir --bin >> "$GITHUB_PATH"
|
|
135
|
+
|
|
136
|
+
- name: Install with mise
|
|
137
|
+
if: matrix.channel == 'mise'
|
|
138
|
+
run: |
|
|
139
|
+
curl -fsSL https://mise.run | sh
|
|
140
|
+
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
141
|
+
for attempt in 1 2 3 4 5; do
|
|
142
|
+
if "$HOME/.local/bin/mise" install -y "pipx:cocoaskills@$CSK_VERSION"; then
|
|
143
|
+
break
|
|
144
|
+
fi
|
|
145
|
+
if [ "$attempt" -eq 5 ]; then
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
sleep $((attempt * 15))
|
|
149
|
+
done
|
|
150
|
+
mkdir -p "$RUNNER_TEMP/csk-mise-wrapper"
|
|
151
|
+
cat > "$RUNNER_TEMP/csk-mise-wrapper/csk" <<EOF
|
|
152
|
+
#!/usr/bin/env bash
|
|
153
|
+
exec "$HOME/.local/bin/mise" exec -y "pipx:cocoaskills@$CSK_VERSION" -- csk "\$@"
|
|
154
|
+
EOF
|
|
155
|
+
chmod +x "$RUNNER_TEMP/csk-mise-wrapper/csk"
|
|
156
|
+
echo "$RUNNER_TEMP/csk-mise-wrapper" >> "$GITHUB_PATH"
|
|
157
|
+
|
|
158
|
+
- name: Install with install.sh
|
|
159
|
+
if: matrix.channel == 'install-sh'
|
|
160
|
+
run: |
|
|
161
|
+
python -m pip install --upgrade pip uv
|
|
162
|
+
curl -fsSL https://cocoaskills.org/install.sh | sh
|
|
163
|
+
python -m uv tool dir --bin >> "$GITHUB_PATH"
|
|
164
|
+
|
|
165
|
+
- name: Verify installed CLI version
|
|
166
|
+
run: |
|
|
167
|
+
actual="$(csk --version)"
|
|
168
|
+
printf '%s\n' "$actual"
|
|
169
|
+
case "$actual" in
|
|
170
|
+
*" $CSK_VERSION") ;;
|
|
171
|
+
*) echo "Expected csk $CSK_VERSION, got: $actual" >&2; exit 1 ;;
|
|
172
|
+
esac
|
|
173
|
+
|
|
174
|
+
- name: Run minimal published-package E2E
|
|
175
|
+
run: |
|
|
176
|
+
root="$(mktemp -d)"
|
|
177
|
+
skills="$root/skills"
|
|
178
|
+
project="$root/project"
|
|
179
|
+
csk_home="$root/csk-home"
|
|
180
|
+
mkdir -p "$skills/skill-a" "$project" "$csk_home"
|
|
181
|
+
|
|
182
|
+
(
|
|
183
|
+
cd "$skills/skill-a"
|
|
184
|
+
git init
|
|
185
|
+
git branch -M main
|
|
186
|
+
printf '%s\n' '---' 'name: skill-a' '---' '' '# Skill A' > SKILL.md
|
|
187
|
+
git add SKILL.md
|
|
188
|
+
git commit -m "skill"
|
|
189
|
+
git tag v1
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
(
|
|
193
|
+
cd "$project"
|
|
194
|
+
git init
|
|
195
|
+
git branch -M main
|
|
196
|
+
printf '.agents/\n.codex/skills/\n' > .gitignore
|
|
197
|
+
cat > Skillfile.json <<'JSON'
|
|
198
|
+
{
|
|
199
|
+
"schema_version": 1,
|
|
200
|
+
"agents": ["codex_cli"],
|
|
201
|
+
"skills": [
|
|
202
|
+
{ "name": "skill-a", "tag": "v1" }
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
JSON
|
|
206
|
+
git add .gitignore Skillfile.json
|
|
207
|
+
git commit -m "project"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
config_file="$csk_home/config.json"
|
|
211
|
+
config_skills="$skills"
|
|
212
|
+
config_project="$project"
|
|
213
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
214
|
+
config_file="$(cygpath -w "$config_file")"
|
|
215
|
+
config_skills="$(cygpath -w "$config_skills")"
|
|
216
|
+
config_project="$(cygpath -w "$config_project")"
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
CONFIG_FILE="$config_file" CONFIG_SKILLS="$config_skills" CONFIG_PROJECT="$config_project" python - <<'PY'
|
|
220
|
+
import json
|
|
221
|
+
import os
|
|
222
|
+
from pathlib import Path
|
|
223
|
+
|
|
224
|
+
config_file = Path(os.environ["CONFIG_FILE"])
|
|
225
|
+
config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
226
|
+
config_file.write_text(
|
|
227
|
+
json.dumps(
|
|
228
|
+
{
|
|
229
|
+
"schema_version": 1,
|
|
230
|
+
"skills_root": os.environ["CONFIG_SKILLS"],
|
|
231
|
+
"default_agents": ["codex_cli"],
|
|
232
|
+
"adapter_mode": "auto",
|
|
233
|
+
"projects": {
|
|
234
|
+
"app": {
|
|
235
|
+
"path": os.environ["CONFIG_PROJECT"],
|
|
236
|
+
"agents": ["codex_cli"],
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
indent=2,
|
|
241
|
+
),
|
|
242
|
+
encoding="utf-8",
|
|
243
|
+
)
|
|
244
|
+
PY
|
|
245
|
+
|
|
246
|
+
export CSK_CONFIG="$config_file"
|
|
247
|
+
csk install app
|
|
248
|
+
test -f "$project/.agents/skills/skill-a/SKILL.md"
|
|
249
|
+
test -f "$project/.agents/skills/skill-a/.csk-install.json"
|
|
250
|
+
csk status app | tee "$root/status.txt"
|
|
251
|
+
grep -q "up-to-date" "$root/status.txt"
|
|
252
|
+
|
|
253
|
+
marker_file="$project/.agents/skills/skill-a/.csk-install.json"
|
|
254
|
+
if command -v cygpath >/dev/null 2>&1; then
|
|
255
|
+
marker_file="$(cygpath -w "$marker_file")"
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
MARKER_FILE="$marker_file" python - <<PY > "$RUNNER_TEMP/content-sha256-${{ matrix.os }}-${{ matrix.channel }}.txt"
|
|
259
|
+
import json
|
|
260
|
+
import os
|
|
261
|
+
from pathlib import Path
|
|
262
|
+
|
|
263
|
+
marker = Path(os.environ["MARKER_FILE"])
|
|
264
|
+
print(json.loads(marker.read_text())["content_sha256"])
|
|
265
|
+
PY
|
|
266
|
+
|
|
267
|
+
- name: Upload content hash
|
|
268
|
+
uses: actions/upload-artifact@v4
|
|
269
|
+
with:
|
|
270
|
+
name: content-hash-${{ matrix.os }}-${{ matrix.channel }}
|
|
271
|
+
path: ${{ runner.temp }}/content-sha256-${{ matrix.os }}-${{ matrix.channel }}.txt
|
|
272
|
+
if-no-files-found: error
|
|
273
|
+
|
|
274
|
+
compare-hashes:
|
|
275
|
+
name: Compare content hashes
|
|
276
|
+
needs: smoke
|
|
277
|
+
if: ${{ always() && !cancelled() }}
|
|
278
|
+
runs-on: ubuntu-latest
|
|
279
|
+
steps:
|
|
280
|
+
- name: Download content hashes
|
|
281
|
+
uses: actions/download-artifact@v4
|
|
282
|
+
with:
|
|
283
|
+
pattern: content-hash-*
|
|
284
|
+
path: hashes
|
|
285
|
+
merge-multiple: true
|
|
286
|
+
|
|
287
|
+
- name: Assert cross-channel hash stability
|
|
288
|
+
run: |
|
|
289
|
+
python - <<'PY'
|
|
290
|
+
from pathlib import Path
|
|
291
|
+
|
|
292
|
+
values = {}
|
|
293
|
+
for path in sorted(Path("hashes").glob("*.txt")):
|
|
294
|
+
values[path.name] = path.read_text(encoding="utf-8").strip()
|
|
295
|
+
|
|
296
|
+
if len(values) < 2:
|
|
297
|
+
raise SystemExit(f"Expected at least two content hash artifacts, got {len(values)}")
|
|
298
|
+
|
|
299
|
+
unique = set(values.values())
|
|
300
|
+
for name, value in values.items():
|
|
301
|
+
print(f"{name}: {value}")
|
|
302
|
+
|
|
303
|
+
if len(unique) != 1:
|
|
304
|
+
raise SystemExit("content_sha256 differs across smoke jobs")
|
|
305
|
+
PY
|
|
306
|
+
|
|
307
|
+
homebrew-smoke:
|
|
308
|
+
name: homebrew / macos-latest
|
|
309
|
+
needs: resolve-version
|
|
310
|
+
runs-on: macos-latest
|
|
311
|
+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.include_homebrew }}
|
|
312
|
+
defaults:
|
|
313
|
+
run:
|
|
314
|
+
shell: bash
|
|
315
|
+
env:
|
|
316
|
+
CSK_VERSION: ${{ needs.resolve-version.outputs.version }}
|
|
317
|
+
steps:
|
|
318
|
+
- name: Set up Python
|
|
319
|
+
uses: actions/setup-python@v5
|
|
320
|
+
with:
|
|
321
|
+
python-version: "3.12"
|
|
322
|
+
|
|
323
|
+
- name: Configure git
|
|
324
|
+
run: |
|
|
325
|
+
git config --global user.email "ci@example.com"
|
|
326
|
+
git config --global user.name "CI"
|
|
327
|
+
git config --global init.defaultBranch main
|
|
328
|
+
git config --global core.autocrlf false
|
|
329
|
+
git config --global core.symlinks false
|
|
330
|
+
|
|
331
|
+
- name: Install with Homebrew
|
|
332
|
+
run: |
|
|
333
|
+
brew tap ivanopcode/csk
|
|
334
|
+
brew install cocoaskills
|
|
335
|
+
|
|
336
|
+
- name: Verify installed CLI version
|
|
337
|
+
run: |
|
|
338
|
+
actual="$(csk --version)"
|
|
339
|
+
printf '%s\n' "$actual"
|
|
340
|
+
case "$actual" in
|
|
341
|
+
*" $CSK_VERSION") ;;
|
|
342
|
+
*) echo "Expected csk $CSK_VERSION, got: $actual" >&2; exit 1 ;;
|
|
343
|
+
esac
|
|
344
|
+
|
|
345
|
+
- name: Run minimal Homebrew E2E
|
|
346
|
+
run: |
|
|
347
|
+
root="$(mktemp -d)"
|
|
348
|
+
skills="$root/skills"
|
|
349
|
+
project="$root/project"
|
|
350
|
+
csk_home="$root/csk-home"
|
|
351
|
+
mkdir -p "$skills/skill-a" "$project" "$csk_home"
|
|
352
|
+
|
|
353
|
+
(
|
|
354
|
+
cd "$skills/skill-a"
|
|
355
|
+
git init
|
|
356
|
+
git branch -M main
|
|
357
|
+
printf '%s\n' '---' 'name: skill-a' '---' '' '# Skill A' > SKILL.md
|
|
358
|
+
git add SKILL.md
|
|
359
|
+
git commit -m "skill"
|
|
360
|
+
git tag v1
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
(
|
|
364
|
+
cd "$project"
|
|
365
|
+
git init
|
|
366
|
+
git branch -M main
|
|
367
|
+
printf '.agents/\n.codex/skills/\n' > .gitignore
|
|
368
|
+
cat > Skillfile.json <<'JSON'
|
|
369
|
+
{
|
|
370
|
+
"schema_version": 1,
|
|
371
|
+
"agents": ["codex_cli"],
|
|
372
|
+
"skills": [
|
|
373
|
+
{ "name": "skill-a", "tag": "v1" }
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
JSON
|
|
377
|
+
git add .gitignore Skillfile.json
|
|
378
|
+
git commit -m "project"
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
cat > "$csk_home/config.json" <<JSON
|
|
382
|
+
{
|
|
383
|
+
"schema_version": 1,
|
|
384
|
+
"skills_root": "$skills",
|
|
385
|
+
"default_agents": ["codex_cli"],
|
|
386
|
+
"adapter_mode": "auto",
|
|
387
|
+
"projects": {
|
|
388
|
+
"app": {
|
|
389
|
+
"path": "$project",
|
|
390
|
+
"agents": ["codex_cli"]
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
JSON
|
|
395
|
+
|
|
396
|
+
export CSK_CONFIG="$csk_home/config.json"
|
|
397
|
+
csk install app
|
|
398
|
+
test -f "$project/.agents/skills/skill-a/SKILL.md"
|
|
399
|
+
csk status app | grep -q "up-to-date"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distributions
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
|
|
26
|
+
- name: Install build tools
|
|
27
|
+
run: python -m pip install --upgrade build twine
|
|
28
|
+
|
|
29
|
+
- name: Build wheel and sdist
|
|
30
|
+
run: python -m build
|
|
31
|
+
|
|
32
|
+
- name: Check metadata
|
|
33
|
+
run: twine check dist/*
|
|
34
|
+
|
|
35
|
+
- name: Generate checksums
|
|
36
|
+
run: |
|
|
37
|
+
python - <<'PY'
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
import hashlib
|
|
40
|
+
|
|
41
|
+
lines = []
|
|
42
|
+
for path in sorted(Path("dist").iterdir()):
|
|
43
|
+
if path.name == "SHA256SUMS":
|
|
44
|
+
continue
|
|
45
|
+
digest = hashlib.sha256(path.read_bytes()).hexdigest()
|
|
46
|
+
lines.append(f"{digest} {path.name}")
|
|
47
|
+
Path("dist/SHA256SUMS").write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
48
|
+
PY
|
|
49
|
+
|
|
50
|
+
- name: Upload Python distributions
|
|
51
|
+
uses: actions/upload-artifact@v4
|
|
52
|
+
with:
|
|
53
|
+
name: python-dist
|
|
54
|
+
path: |
|
|
55
|
+
dist/*.tar.gz
|
|
56
|
+
dist/*.whl
|
|
57
|
+
|
|
58
|
+
- name: Upload checksums
|
|
59
|
+
uses: actions/upload-artifact@v4
|
|
60
|
+
with:
|
|
61
|
+
name: checksums
|
|
62
|
+
path: dist/SHA256SUMS
|
|
63
|
+
|
|
64
|
+
publish-testpypi:
|
|
65
|
+
name: Publish to TestPyPI
|
|
66
|
+
needs: build
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
if: startsWith(github.ref_name, 'v') && (contains(github.ref_name, '-rc') || contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta'))
|
|
69
|
+
environment: testpypi
|
|
70
|
+
permissions:
|
|
71
|
+
contents: read
|
|
72
|
+
id-token: write
|
|
73
|
+
steps:
|
|
74
|
+
- name: Download distributions
|
|
75
|
+
uses: actions/download-artifact@v4
|
|
76
|
+
with:
|
|
77
|
+
name: python-dist
|
|
78
|
+
path: dist
|
|
79
|
+
|
|
80
|
+
- name: Publish to TestPyPI
|
|
81
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
82
|
+
with:
|
|
83
|
+
repository-url: https://test.pypi.org/legacy/
|
|
84
|
+
packages-dir: dist/
|
|
85
|
+
|
|
86
|
+
publish-pypi:
|
|
87
|
+
name: Publish to PyPI and GitHub Releases
|
|
88
|
+
needs: build
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
if: startsWith(github.ref_name, 'v') && !contains(github.ref_name, '-')
|
|
91
|
+
environment: pypi
|
|
92
|
+
permissions:
|
|
93
|
+
contents: write
|
|
94
|
+
id-token: write
|
|
95
|
+
steps:
|
|
96
|
+
- name: Download distributions
|
|
97
|
+
uses: actions/download-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: python-dist
|
|
100
|
+
path: dist
|
|
101
|
+
|
|
102
|
+
- name: Publish to PyPI
|
|
103
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
104
|
+
with:
|
|
105
|
+
packages-dir: dist/
|
|
106
|
+
|
|
107
|
+
- name: Download checksums
|
|
108
|
+
uses: actions/download-artifact@v4
|
|
109
|
+
with:
|
|
110
|
+
name: checksums
|
|
111
|
+
path: dist
|
|
112
|
+
|
|
113
|
+
- name: Create GitHub Release
|
|
114
|
+
uses: softprops/action-gh-release@v2
|
|
115
|
+
with:
|
|
116
|
+
files: dist/*
|
|
117
|
+
fail_on_unmatched_files: true
|
|
118
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Python
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
.Python
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
env/
|
|
12
|
+
ENV/
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
build/
|
|
19
|
+
dist/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
|
|
22
|
+
# Editor and local files
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
*.swp
|
|
26
|
+
*.swo
|
|
27
|
+
*.log
|
|
28
|
+
|
|
29
|
+
# setuptools-scm
|
|
30
|
+
src/csk/_version.py
|
|
31
|
+
|
|
32
|
+
# CocoaSkill generated runtime/install artifacts
|
|
33
|
+
.agents/
|
|
34
|
+
.claude/skills/
|
|
35
|
+
.codex/skills/
|
|
36
|
+
.gemini/skills/
|
|
37
|
+
.cursor/rules/
|
|
38
|
+
|